2009-07-21 2 views
5

Я пытаюсь решить проблему ниже.SQL Elaborate Joins 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 

Если я ищу что-то с теми же атрибутами, что Asset-А, то он должен определить Asset-B, так как актив-B имеет все те же атрибуты, как Asset-A (он должен отбросить тяжелый, поскольку Asset-A не указал ничего другого или подобного). Кроме того, если бы я хотел, чтобы атрибуты только для Asset-A AND Asset-B были распространены, как бы я мог это получить?

кажется простым, но я не могу прибить его ...

Фактическая таблица Я использую, почти точно Table2, просто ассоциация с AssetID, и AttributeId так: PK: Id
INT: AssetID
INT: AttributeId

Я только включал идею таблицы активов упрощать вопрос.

+3

Почему -1? Совершенно действительный SQL-запрос. +1 –

+0

Любой вопрос, который выглядит так: «Я не знаю, как работает объединение», довольно корыстный и не имеет возможности использовать его за пределами оригинального плаката. –

+0

@Mark: этот вопрос * far * beyond «как работает объединение». – 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

Итак, у вас есть атрибут таблицы с атрибутом столбца? У вас есть NULL в атрибуте, потому что иначе COUNT (ta2. [Attribute]) не отличается от COUNT (*), за исключением того, что он медленнее. Второй 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.Anything ... (Идентификатор из нескольких частей «ata.AttributeId» не может быть связан.) – Praesidium

+0

@Praesidium: см. Пост-обновление. – Quassnoi

0

Я не совсем понимаю первую часть вашего вопроса, определение активов на основе их атрибутов.

Создание некоторых предположений об именах столбцов, следующий запрос будет давать общие атрибуты между активами-A и Asset-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

Или активы, которые имеют только один общий атрибут ... Таким образом, он возвратит Asset-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

Найти все активы, которые имеют каждый атрибут, который " 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 
    ) 
    ) 

Т.е.,« найдите любые активы, в которых нет атрибута А это также не является атрибутом этого актива ».

Найти все активы, которые имеют одни и те же атрибуты, как «А»:

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 
    ) 
    ) 

Ie «найти какие-либо активы, где нет никакого атрибута, который также не является атрибутом этого актива, и где нет атрибута этого актива, который также не является атрибутом 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() 

Я думал, что перевод этого обратно в SQL с LinqPad приведет к довольно SQL-запросу. Однако это не было :). DevProducts - это моя тестовая таблица с заголовком Product и Attribute. Я думал, что я отправлю запрос LINQ в любом случае, может быть полезно людям, которые играют с LINQ.

Если вы можете оптимизировать запрос LINQ выше, пожалуйста, дайте мне знать (это может привести к улучшению SQL;))

+0

Я могу заставить его работать в LINQ, но проблема в том, что LINQ медленнее, чем просто создавать это в хранимой процедуре или что-то с пуском выполнения. Если бы я собирался сделать что-то подобное, я бы использовал Compiled Query, чтобы ускорить его. – Praesidium

0

Я использую следующие 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') 

Edit:

Я оставил AND Asset != 'A' из оговорки второго фрагмента WHERE для краткости