2009-08-18 6 views
0

Je rencontre des problèmes avec un autre problème SQL. J'ai vraiment besoin de prendre un peu de temps pour apprendre cela correctement.Sélectionner les lignes de la requête avec une clé étrangère distincte?

De toute façon j'ai cette requête que quelqu'un d'autre a écrit et il obtient des valeurs de quelques tables différentes.

Maintenant plus d'un élément peut avoir le même ProductID. Il peut donc y avoir 3 éléments retournés tous avec le même ProductID mais ils ont des descriptions différentes, etc.

Je veux sélectionner seulement 1 article par ProductID. J'ai essayé d'utiliser DISTINCT et grouper par mais je reçois beaucoup d'erreurs. C'est aussi pour une base de données ACCESS.

Je pense que c'est à cause de la logique utilisée dans la requête select qui gâche mon groupement.

Voici la requête (je l'ai essayé de formater un peu mieux, utilisé un outil en ligne, mais il est encore un énorme gâchis)

SELECT tblproducts.productid, 
    tblproducts.categorycode, 
    tblproducts.scaletitle, 
    tblproducts.picture, 
    tblitems.cost, 
    tblitems.modelnumber, 
    tblitems.itemid, 
    Iif([tblitems]![tradeapproved],Iif(([tblitems]![markup]/100) <> 0,(Iif(([tblitems]![supplierdiscount]/100) <> 0, 
                       [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount]/100)), 
                       [tblitems]![cost])) * ([tblitems]![markup]/100), 
             0) + Iif(([tblitems]![supplierdiscount]/100) <> 0, 
               [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount]/100)), 
               [tblitems]![cost]) + [tblitems]![tradeapprovedcost] + [tblitems]![shippingcost], 
     Iif(([tblitems]![markup]/100) <> 0,(Iif(([tblitems]![supplierdiscount]/100) <> 0, 
                [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount]/100)), 
                [tblitems]![cost])) * ([tblitems]![markup]/100), 
      0) + Iif(([tblitems]![supplierdiscount]/100) <> 0, 
         [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount]/100)), 
         [tblitems]![cost]) + [tblitems]![shippingcost]) AS price 
FROM  (tblitems 
     INNER JOIN tblproducts 
     ON tblitems.productid = tblproducts.productid) 
    INNER JOIN tblsuppliers 
     ON tblproducts.supplierid = tblsuppliers.supplierid 
WHERE tblproducts.categorycode = 'BS' 
    AND tblitems.tradeapproved = 0 
    AND tblsuppliers.active = on 
    AND tblitems.isaccessory = false 
ORDER BY Iif([tblitems]![tradeapproved],Iif(([tblitems]![markup]/100) <> 0,(Iif(([tblitems]![supplierdiscount]/100) <> 0, 
                       [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount]/100)), 
                       [tblitems]![cost])) * ([tblitems]![markup]/100), 
             0) + Iif(([tblitems]![supplierdiscount]/100) <> 0, 
               [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount]/100)), 
               [tblitems]![cost]) + [tblitems]![tradeapprovedcost] + [tblitems]![shippingcost], 
     Iif(([tblitems]![markup]/100) <> 0,(Iif(([tblitems]![supplierdiscount]/100) <> 0, 
                [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount]/100)), 
                [tblitems]![cost])) * ([tblitems]![markup]/100), 
      0) + Iif(([tblitems]![supplierdiscount]/100) <> 0, 
         [tblitems]![cost] - ([tblitems]![cost] * ([tblitems]![supplierdiscount]/100)), 
         [tblitems]![cost]) + [tblitems]![shippingcost]) 

Déposez une solution rapide pour cela? Merci

+2

Ce code est un labyrinthe sanglant. J'ai essayé le formatage mais j'ai perdu patience jusqu'à tard dans la soirée. Pouvez-vous s'il vous plaît le formater à quelque chose de lisible? Ou peut-être afficher une version simplifiée? – Eric

+0

@Eric, même histoire ici ... essayé de le mettre en forme, mais a abandonné. –

+0

Ok, je sais que c'est énorme, en plus du code qu'on m'a donné ça en 12 fois comme ça! C'est un cauchemar de travailler avec, je vais faire les modifications et poster un meilleur – ddd

Répondre

1

Eh bien, puisque vous avez dit que vous voulez apprendre ce genre de choses:

Une jointure interne se connecter à des articles de ProductId mais se traduira par un ensemble complet. Donc, si vous avez 3 ProductIds et 1 article vous obtiendrez

ProdId ItemId Description 
1  1  Handy Dandy Randy Sandy! 
2  1  Easily Accessible personal grooming comb. 
3  1  This item provides a man or woman with extra re... 

Donc ce que vous voulez vraiment faire est d'obtenir toutes les itemID:

select ItemId from Item_tbl 

Et puis une boucle sur chaque résultat, obtenir un ProductId Maintenant, toute personne qui suggère une boucle avec SQL est abaissée, et (habituellement) à juste titre. Mais c'est une requête difficile à faire, car ce n'est pas quelque chose que les gens font habituellement.

Vous étiez dans les bonnes lignes avec group by. Grouper dit "consolider toutes les lignes qui ont une colonne distincte X" où la colonne X serait ItemId. Donc: Donnez-moi une ligne par ItemId.

Vous devez maintenant choisir un ProductId de ces 3 produits avec ItemId 1. Le tricheur façon de le faire est de ne pas choisir un ProductId au hasard mais plutôt un productId qui correspond à une fonction d'agrégation particulière. Les plus courants sont min et max.

select 
    ItemId, 
    max(ProductId) 
from Itemtbl i 
inner join Producttbl p 
    on i.itemid = p.itemId 
group by ItemId 

Ceci aura le plus grand ProductId pour chaque ItemId. Vous pouvez faire la même chose pour obtenir le minimum. Maintenant, ce qui est plus compliqué est de trouver un ProductId qui correspond à un critère - disons le plus récemment mis à jour. Ce que vous voulez dire est "sélectionnez l'ItemId, et le max (updatedDate), puis tirez le ProductId de cette date mise à jour max le long de - mais cela ne fonctionne pas dans sql (cher dieu que je souhaite qu'il a fait cependant).

Cette requête donnera de mauvais résultats:

select 
    ItemId, 
    max(ProductId), 
    max(updatdedDate) 
from Itemtbl i 
inner join Producttbl p 
    on i.itemid = p.itemId 
group by ItemId 

Parce que le max ProductId ne vient pas nécessairement de la ligne avec le maximum updatedDate.

Au lieu de cela, vous devez écrire une requête qui fait cela:

  1. Sélectionne le ItemId (par exemple 5), et la date maxUpdated (par exemple 5/5/2005)
  2. Saute au Products_tbl et trouve le ProductId dont ItemId est 5 et updatedDate est 5/5/2005

Cette requête est laissée en tant qu'exercice. (mais il y a un bug si deux produits ont la même date de dernière mise à jour et la même ItemId!)

+0

J'aime votre réponse et l'effort. Cependant, cela ne m'a pas vraiment aidé tout à l'heure. Je connais les bases de SQL mais cette requête est juste un cauchemar avec lequel travailler et peu importe ce que j'essaie, je reçois beaucoup d'erreurs, je pense que c'est à voir avec les instructions if. VS2008 ne peut même pas analyser la requête! Merci encore – ddd

+0

J'ai essayé d'encapsuler la requête d'origine en tant que table dérivée et en sélectionnant les propriétés spécifiques. quand j'essaye de faire le maximum sur itemId j'obtiens une erreur qu'il n'y a aucune fonction d'agrégation pour productId – ddd

+0

Il n'y a aucune fonction d'agrégation pour productId; vous n'avez pas de clause "group by", vous ne pouvez donc pas utiliser max. Franchement, la meilleure façon d'aborder cela est de le décomposer. Examinez les tables que vous avez, les PK et FK que vous avez, puis déterminez ce que vous essayez d'obtenir. Tel qu'il est, il ressemble à spaghetti (même re-formaté). –

1

Première étape pour augmenter la lisibilité est de créer une vue pour votre tblItems qui comprend la logique de fantaisie pour le prix, par exemple :

Voir [vwItemsWithAdjustedCost]

SELECT 
    ProductID, 
    TradeApproved, 
    IsAccessory, 
    Cost, 
    ModelNumber, 
    ItemID, 
    IIf(
     (SupplierDiscount/100) <> 0, 
     Cost - (Cost * (SupplierDiscount/100)), 
     Cost 
    ) AS AdjustedCost 
FROM tblItems   

Voir [vwItemsWithPrice]

SELECT 
    ProductID, 
    TradeApproved, 
    IsAccessory, 
    Cost, 
    ModelNumber, 
    ItemID, 
    IIf(
     (Markup/100) <> 0, 
     AdjustedCost * (Markup/100), 
     0 
    ) 
    + AdjustedCost 
    IIf(
     TradeApproved, 
     TradeApprovedCost, 
     0 
    ) 
    + ShippingCost AS Price 
FROM vwItemsWithAdjustedCost 

Suivant vous devez décider quels sont les critères pour choisir un article parmi ceux qui correspondent au même ProductID, si 3 articles ont le même ID que vous voulez montrer?

Comme l'a déclaré Tom, un moyen facile est d'obtenir que le premier (le plus bas) ID qui correspond, quelque chose comme ceci:

SELECT 
    P.ProductID, 
    P.CategoryCode, 
    P.ScaleTitle, 
    P.Picture, 
    IP.Cost, 
    IP.ModelNumber, 
    IP.ItemID, 
    IP.Price 
FROM 
    tblProducts P 
    INNER JOIN (
     SELECT 
      ProductID, 
      MIN(ItemID) AS MinItemID 
     FROM tblItems I 
     GROUP BY ProductID 
    ) S 
     ON S.ProductID = P.ProductID 
    INNER JOIN vwItemsWithPrice IP 
     ON IP.ItemID = S.MinItemID 
WHERE 
    P.CategoryCode = 'BS' 
    AND IP.TradeApproved = 0 
    AND IP.IsAccessory = false 
ORDER BY IP.Price 

Cela dit pour chaque ProductID, donnez-moi le premier (le plus bas) ItemID de tblItems, et en utilisant cette jointure à mon avis.

Espérons que cela aide!

+0

Merci pour la réponse, ça aide. J'ai essayé votre méthode mais je suis encore un peu coincé. J'ai votre dernier extrait, mais sans l'endroit et la commande par et sélectionnez simplement * pour plus de simplicité. Je reçois une erreur de syntaxe dans l'accès pointant vers la dernière jointure interne de la vue.J'ai même essayé de substituer la vue à la table des objets, donc je savais qu'il n'y aurait pas de problème mais toujours la même erreur. – ddd

+0

L'erreur est opérateur d'erreur de syntaxe manquante et affiche le code S ON S.ProductID = P.ProductID INNER JOIN (SELECT ItemID de tblItems) IP ON IP.ItemID = S.MinItemID – ddd

+0

Vous utilisez Access et Je pense qu'il faut imbriquer les jointures (depuis un moment que je l'ai utilisé, peut-être tort), il suffit de mettre des parenthèses autour de la première jointure, FROM (tblProducts P ... ON S.ProductID = P.ProductID) INNER JOIN .. . –

Questions connexes