2009-07-21 8 views
5

私は以下の問題を解決しようとしています。SQL Elaborate Join Query

私はそれが可能なように感じますが、私はそれを得るように見えません。ここで

はシナリオです:

Table 1 (Assets) 
1 Asset-A 
2 Asset-B 
3 Asset-C 
4 Asset-D 

Table 2 (Attributes) 
1 Asset-A Red 
2 Asset-A Hard 
3 Asset-B Red 
4 Asset-B Hard 
5 Asset-B Heavy 
6 Asset-C Blue 
7 Asset-C Hard 

私は資産-Bは、資産-Aなど、すべて同じ属性を持っているので、それは資産-Bを特定しなければならない資産-Aと同じ属性を持つ何かを探しています場合には(Asset-Aは異なるものや類似のものを指定していないので、重いものを破棄すべきです)。また、資産Aと資産Bの属性だけが共通したい場合は、どうすればよいでしょうか?

私が使用しています実際のテーブルには、ほとんど正確に表2、AssetIdの単純協会などAttributeId単純なようだが、私はそれを爪することはできません...

: PK:同上
INT:AssetId
INT:私は唯一の問題を簡単にするために、資産のテーブルのアイデアを含ま


をAttributeId。

+3

なぜ-1ための第二のスニペットのWHERE句のうちのAND Asset != 'A'を残し?完全に有効なSQLの質問。 +1 –

+0

"私はどのように結合しているか分かりません"のような質問は、かなり自立しており、元のポスターを超えた使用はありません。 –

+0

@マーク:この質問は「遠くに」「どのように結合するか」を超えています。 – Quassnoi

答えて

0

このソリューションは、入力のおかげで、規定どおりに動作します。

WITH Atts AS 
(
    SELECT 
    DISTINCT 
     at1.[Attribute] 
    FROM 
     Attribute at1 
    WHERE 
     at1.[Asset] = 'Asset-A' 
) 

SELECT 
    DISTINCT 
    Asset, 
    (
     SELECT 
      COUNT(ta2.[Attribute]) 
     FROM 
      Attribute ta2 
     INNER JOIN 
      Atts b 
      ON 
       b.[Attribute] = ta2.[attribute] 
     WHERE 
      ta2.[Asset] = ta.Asset 
    ) 
    AS [Count] 
FROM 
    Atts a 
INNER JOIN 
    Attribute ta 
    ON 
    a.[Attribute] = ta.[Attribute] 
+0

したがって、attribute属性のテーブル属性がありますか? COUNT(ta2。[Attribute])がCOUNT(*)と異ならず、遅いという点を除いて、属性にNULLがありますか。 2番目のJOINは重複しているようです。それでも、作業を完了させるかもしれません:-)) – wqw

+0

これは実際のテーブル名やカラム名ではなく、私がやろうとしていることの素早い表現です! – Praesidium

4
SELECT ato.id, ato.value 
FROM (
     SELECT id 
     FROM assets a 
     WHERE NOT EXISTS 
       (
       SELECT NULL 
       FROM attributes ata 
       LEFT JOIN 
         attributes ato 
       ON  ato.id = ata.id 
         AND ato.value = ata.value 
       WHERE ata.id = 1 
         AND ato.id IS NULL 
       ) 
     ) ao 
JOIN attributes ato 
ON  ato.id = ao.id 
JOIN attributes ata 
ON  ata.id = 1 
     AND ata.value = ato.value 

、またはSQL Server 2005中(サンプルデータを確認すると):

WITH assets AS 
     (
     SELECT 1 AS id, 'A' AS name 
     UNION ALL 
     SELECT 2 AS id, 'B' AS name 
     UNION ALL 
     SELECT 3 AS id, 'C' AS name 
     UNION ALL 
     SELECT 4 AS id, 'D' AS name 
     ), 
     attributes AS 
     (
     SELECT 1 AS id, 'Red' AS value 
     UNION ALL 
     SELECT 1 AS id, 'Hard' AS value 
     UNION ALL 
     SELECT 2 AS id, 'Red' AS value 
     UNION ALL 
     SELECT 2 AS id, 'Hard' AS value 
     UNION ALL 
     SELECT 2 AS id, 'Heavy' AS value 
     UNION ALL 
     SELECT 3 AS id, 'Blue' AS value 
     UNION ALL 
     SELECT 3 AS id, 'Hard' AS value 
     ) 
SELECT ato.id, ato.value 
FROM (
     SELECT id 
     FROM assets a 
     WHERE a.id <> 1 
       AND NOT EXISTS 
       (
       SELECT ata.value 
       FROM attributes ata 
       WHERE ata.id = 1 
       EXCEPT 
       SELECT ato.value 
       FROM attributes ato 
       WHERE ato.id = a.id 
       ) 
     ) ao 
JOIN attributes ato 
ON  ato.id = ao.id 
JOIN attributes ata 
ON  ata.id = 1 
     AND ata.value = ato.value 
+0

私はそれを働かせるようには見えません。ataにバインドできないようです。何か...(複数の部分の識別子「ata.AttributeId」はバインドできませんでした) – Praesidium

+0

@Praesidium:post updateを参照してください。 – Quassnoi

0

私は完全に自分の属性に基づいて資産を識別し、あなたの質問の最初の部分を理解していません。

カラム名に関するいくつかの仮定を作り、次のクエリは、資産Aと資産Bの間に共通の属性をもたらすであろう:

SELECT [Table 2].Name 
FROM [Table 2] 
JOIN [Table 1] a ON a.ID = [Table 2].AssetID AND a.Name = 'Asset-A' 
JOIN [Table 1] b ON b.ID = [Table 2].AssetID AND b.Name = 'Asset-B' 
GROUP BY [Table 2].Name 
0
Select * From Assets A 
    Where Exists 
     (Select * From Assets 
     Where AssetId <> A.AssetID 
      And (Select Count(*) 
       From Attributes At1 Join Attributes At2 
        On At1.AssetId <> At2.AssetId 
         And At1.attribute <> At2.Attribute 
       Where At1.AssetId = A.AssetId Asset) = 0) 
    And AssetId = 'Asset-A' 
+0

ここには存在しないはずですが、属性のないアセットも返されます... – Praesidium

+0

または1つのアトリビュートだけが共通するアセット...それはアセット-Cが返されます。青ではなく、Asset-A – Praesidium

0
select at2.asset, count(*) 
from  attribute at1 
inner join attribute at2 on at1.value = at2.value 
where at1.asset = "Asset-A" 
and at2.asset != "Asset-A" 
group by at2.asset 
having count(*) = (select count(*) from attribute where asset = "Asset-A"); 
+0

これは何も返されないようです...すべての資産は失格です。 – Praesidium

+0

これは、内部クエリのテーブル名に「属性」ではなく「属性」を使用したためです。修正されました。もちろん、実際のテーブル名を使用する必要があります。私は彼らが何であるか分からない。 –

0

「そのすべての属性を持っているすべての資産を探します(追加の属性を持つこともあります):

SELECT Other.ID 
FROM Assets Other 
WHERE 
    Other.AssetID <> 'Asset-A' -- do not return Asset A as a match to itself 
    AND NOT EXISTS (SELECT NULL FROM Attributes AttA WHERE 
    AttA.AssetID='Asset-A' 
    AND NOT EXISTS (SELECT NULL FROM Attributes AttOther WHERE 
     AttOther.AssetID=Other.ID AND AttOther.AttributeID = AttA.AttributeID 
    ) 
    ) 

つまり、「属性がないこれはこの資産の属性でもありません」。

「A」とまったく同じ属性持っているすべての資産検索:

SELECT Other.ID 
FROM Assets Other 
WHERE 
    Other.AssetID <> 'Asset-A' -- do not return Asset A as a match to itself 
    AND NOT EXISTS (SELECT NULL FROM Attributes AttA WHERE 
    AttA.AssetID='Asset-A' 
    AND NOT EXISTS (SELECT NULL FROM Attributes AttOther WHERE 
     AttOther.AssetID=Other.ID 
     AND AttOther.AttributeID = AttA.AttributeID 
    ) 
    ) 
    AND NOT EXISTS (SELECT NULL FROM Attributes AttaOther WHERE 
    AttaOther.AssetID=Other.ID 
    AND NOT EXISTS (SELECT NULL FROM Attributes AttaA WHERE 
     AttaA.AssetID='Asset-A' 
     AND AttaA.AttributeID = AttaOther.AttributeID 
    ) 
    ) 

すなわち、「また、この資産の属性ではありませんAの属性がないすべての資産を見つけて、この資産の属性はAの属性でもありません。

0

資産としてすべて同じ属性を持つすべての資産を探す:

select att2.Asset from attribute att1 
inner join attribute att2 on att2.Attribute = att1.Attribute and att1.Asset <> att2.Asset 
where att1.Asset = 'Asset-A' 
group by att2.Asset, att1.Asset 
having COUNT(*) = (select COUNT(*) from attribute where Asset=att1.Asset) 
0
私はLINQでこれを行うと、その後で後方私の方法を働かせることができるかもしれないと思った

var result = from productsNotA in DevProducts 
      where productsNotA.Product != "A" && 
      (
       from productsA in DevProducts 
       where productsA.Product == "A" 
       select productsA.Attribute 
      ).Except 
      (
       from productOther in DevProducts 
       where productOther.Product == productsNotA.Product 
       select productOther.Attribute 
      ).Single() == null 
      select new {productsNotA.Product}; 

result.Distinct() 

これをLinqPadを使用してSQLに変換すると、かなりのSQLクエリが生成されると考えました。しかしそれはなかった:)。 DevProductsは製品と属性の列を持つ私のテストテーブルです。とにかくLINQクエリを投稿すると思っていましたが、LINQを使いこなしている人には便利かもしれません。

あなたは上記のLINQクエリを最適化することができる場合、私に知らせてください(それが良いSQLになる場合があります;))

+0

私はそれをLINQで動作させることができますが、LINQはストアドプロシージャや実行パスを持つもので単純に生成するよりも遅いという問題があります。このようなことをやろうとすれば、コンパイルされたクエリを使用してスピードアップします。 – Praesidium

0

私は2番目の質問は

簡単で、次のDDLに

CREATE TABLE Attributes (
    Asset  VARCHAR(100) 
    , Name  VARCHAR(100) 
    , UNIQUE(Asset, Name) 
    ) 

を使用しています

SELECT Name 
FROM  Attributes 
WHERE Name IN (SELECT Name FROM Attributes WHERE Asset = 'A') 
     AND Asset = 'B' 

最初の質問は、より難しいものではありません

SELECT Asset 
FROM  Attributes 
WHERE Name IN (SELECT Name FROM Attributes WHERE Asset = 'A') 
GROUP BY Asset 
HAVING COUNT(*) = (SELECT COUNT(*) FROM FROM Attributes WHERE Asset = 'A') 

編集:

私は簡潔