2015-05-24 3 views
4

У меня есть 2 таблицы: -Сравнить 2 результирующие наборы без INTERSECT

ITEM(ITEM_ID, ITEM_NAME) 

STATS(ITEM_ID, STAT_ID, STAT_VALUE) 

Я хотел бы вернуть ITEM_IDs с точно такой же STATS, но это не на SQL Server Compact (не EXCEPT или INTERSECT)

Например:

STATS:- 
1 12 100 
1 13 500 
2 12 200 
2 14 300 
3 12 100 
3 13 500 
4 12 100 

Если возвращение строки для 1 и 3 (такого же статистика/значения 12/100 и 13/500)

Возможно ли без INTERSECT?

+0

Являются ли эти столбцы NULLable? – dnoeth

+0

Как вы используете 'INTERSECT' для этих результатов? ;). –

+0

Что делать, если есть строка '5 13 500', если она будет включена в результат или только если есть' 5 12 100'? – dnoeth

ответ

2

Я не уверен, что если SQL Server Compact поддерживает внутренние запросы, но это понятие должно работать:

select distinct a.item_id 
     from stats a 
     where exists(select 1 
          from stats b 
          where a.stat_d=b.stat_id 
          and a.stat_value=b.stat_value) 
+0

Спасибо, но это приведет к появлению нежелательных строк, таких как 4 (12/100 существует, но не 13/500) – Christian

3

Я получил это совершенно неправильно в первый раз :-)

Стандартные подходы к «найти одинаковые наборы «трудно понять, и производительность, как правило, плохо для больших таблиц, поскольку они включают в себя сравнение всего со всем остальным (подобно CROSS JOINs).

AFAIK SQL Server CE поддерживает функции XML, тоже, так что лучший способ это один описал Владимир Баранов в одном из существующих ответов:

with cte as 
(-- group concat all rows for one ITEM_ID into one big string 
    SELECT distinct ITEM_ID, 
    (select '#' + rtrim(STAT_ID) + ',' + rtrim(STAT_VALUE) 
     from STATS as t2 
     where t1.ITEM_ID = t2.ITEM_ID ORDER BY STAT_ID FOR XML PATH('')) as rowsConcat 
    FROM STATS as t1 
), 
cnts as 
(-- how many rows exist for that concatenated string? 
    select * 
    ,count(*) 
     over (partition by rowsConcat) as cnt 
    from cte 
) 
select ITEM_ID 
    ,dense_rank() -- assign the same group number to the duplicates 
    over(order by rowsConcat) as duplicateGroup 
from cnts 
where cnt > 1 -- more than one 

fiddle

+0

Это ничего не вернет ... – Christian

+0

@Fred: Да, я не читал данные правильно. – dnoeth

+0

@Fred: Попробуйте новый, это должно работать :-) – dnoeth

2

INTERSECT
Возвращает любые различные значения, возвращаемые как запросом слева, так и справа от операнда INTERSECT.

Альтернатива использования INTERSECT использует JOIN так:

SELECT A.* 
FROM A -- [A: ID, Name] 
INTERSECT 
SELECT B.* 
FROM B -- [B: ID, Name] 

Равен

SELECT DISTINCT A.* 
FROM A 
JOIN (
    SELECT B.* 
    FROM B) B1 ON A.ID = B1.ID AND A.Name = B1.Name 

или с помощью EXISTS:

SELECT DISTINCT A.* 
FROM A 
WHERE EXISTS (
    SELECT 1 
    FROM B WHERE A.ID = B.ID AND A.Name = B.Name) 

Попробуйте этот запрос:

SELECT DISTINCT s1.STAT_ID, s1.STAT_VALUE 
FROM STATS s1 
    JOIN 
    STATS s2 ON s1.ITEM_ID <> s2.ITEM_ID 
      AND s1.STAT_ID = s2.STAT_ID 
      AND s1.STAT_VALUE = s2.STAT_VALUE 
+0

Такая же проблема, как и первый ответ: это приведет к возврату нежелательных строк (1 строка существует, но не другая) – Christian

+0

@Fred Если я знаю 'Как вы используете INTERSECT для этих результатов?' Я могу помочь вам больше, здесь я покажу несколько способов для вас не использовать 'INTERSECT';). –

+0

Я понял это, потому что я обычно использовал INTERSECT с другими SGBD для этих типов запросов (ORACLE, Sybase и т. Д.), И это не относится к SQL CE. – Christian

4

использовать внутреннее соединение в ITEM стола и использовать при условии, какой вы хотите видеть на этом столе

3

Вот как я бы подойти к такой задаче.

Шаг 1. Имейте функцию/метод для объединения значений в нескольких столбцах в один столбец. В вашем случае мы хотим поставить два значения STAT_ID и STAT_VALUE вместе. В этом случае достаточно простого преобразования в строку и конкатенацию.Таким образом, строка с двумя колоннами:

STAT_ID STAT_VALUE 
12  100 

становится строку с одной колонки:

single_value 
12_100 

Результат этого преобразования должен быть таблица, как это:

ITEM_ID single_value 
1  12_100 
1  13_500 
2  12_200 
2  14_300 
3  12_100 
3  13_500 
4  12_100 

Шаг 2 . Есть функция Aggregate, которая принимает значения в нескольких строках и возвращает одно значение в виде длинной конкатенированной строки. Это может быть функция CLR, функция T-SQL или конструкция FOR XML. Вы можете выбрать один из них в зависимости от того, что поддерживает SQL Server CE.

Результат этого преобразования должен быть таблица, как это:

ITEM_ID aggregated_single_value 
1  12_100__13_500 
2  12_200__14_300 
3  12_100__13_500 
4  12_100 

Шаг 3. После того как вы этот результат вы можете просто GROUP BY aggregated_single_value и COUNT сколько ITEM_IDs с точно таким же набором значений у вас есть. Затем вернитесь только те ITEM_IDs, которые HAVING насчитать более 1.

aggregated_single_value Count 
12_100__13_500   2 
12_200__14_300   1 
12_100     1 

Edit

Общий подход по-прежнему выполняется с ограничениями SQL Server CE.

  • У него нет общих выражений-таблиц - используйте явные временные таблицы для каждого шага.
  • У него нет FOR XML, определенные пользователем функции, CLR - выполнить агрегацию «вручную». Похоже на это supports cursors. Откройте курсор - сканируйте таблицу один раз с правильным порядком, суммируйте значения и сохраните их во временную таблицу.
  • Поддерживает ли он такие крупные типы, как varbinary(max) или varchar(max)? Если да - отлично, если нет - вы будете ограничены varchar(8000) или varbinary(8000). Если в таблице STATS имеется не более двух (или так) строк для одного и того же ITEM_ID, то достаточно 8000 байт.

Также существует, по крайней мере, один простой грубый способ ограничить количество строк, обработанных курсором. Сначала сделайте простой подсчет строк для каждого ITEM_ID в таблице STATS и оставьте только те IDs, которые имеют соответствующий счет. Другими словами, отфильтруйте очевидные несоответствия. Этот шаг устранит ID=4 из вашего примера.

+0

Спасибо за идею, но SQL Server CE, похоже, ничего не поддерживает для агрегации строк напрямую ... – Christian

+0

Есть ли у пользователя -определенные функции? В принципе, вам нужно найти способ выполнить 'group-concat' для вашей версии SQL Server. Кстати, какая именно версия вашего сервера? –

+0

Это SQL Server CE 4.0, многие «не поддерживаемые» функции: https://technet.microsoft.com/en-us/library/bb896140%28v=sql.110%29.aspx – Christian

Смежные вопросы