2013-10-01 4 views
1

Я бы предпочел использовать логику набора, а не итерировать по таблице с помощью курсора или что-то в этом роде, но если это то, что нужно, это можно сделать.Сложная логика SQL Exclude с операциями на основе набора

Я в основном готовлю представление в хранимой процедуре, которая будет использоваться в другом месте для BI. Сейчас хранимая процедура - это просто оператор выбора, вытягивающий из разных таблиц с приличным количеством объединений и другой случайной логикой.

Вот пример того, как выглядят таблицы. Во-первых, таблица, которая будет возвращена, во-вторых, какие исключения пользователь хочет сделать. Example

Я хочу посмотреть каждую запись в таблице исключений, а затем применить ее как фильтр к первой таблице, чтобы устранить все строки, в которых находятся элементы. (Это будет немного сложнее в будущем, потому что они могут выбрать, чтобы исключить весь LocationCode, который затем будет каскадом через все WarehouseCodes и все под ним. Это в основном иерархия, но я хочу, чтобы общая идея была опущена).

Я не был уверен, как это сделать с НЕ СУЩЕСТВУЮЩИМ, поскольку мне нужно идти по строкам. Я не уверен, что мне нужно использовать курсор или перебрать по другому пути. Мне интересно, есть ли другой инструмент в SQL, о котором я не знаю.

Любые предложения по эффективному устранению строк на основе других значений таблиц были бы оценены, спасибо.

ответ

1

, если вы хотите, чтобы получить целые строки из Table1, кроме строк, которые имеют похожести в Table2, вы можете сделать это:

select * -- Column list here 
from Table1 as t 
where 
    not exists (
     select t.LocationCode, t.WarehouseCode, t.WarehouseName, t.StorageAddress 
     intersect 
     select t2.LocationCode, t2.WarehouseCode, t2.WarehouseName, t2.StorageAddress 
     from Table2 as t2 
    ) 

или более удобный

select * -- Column list here 
from Table1 as t 
where 
    not exists (
     select * 
     from Table2 as t2 
     where 
      t2.LocationCode = t.LocationCode and 
      t2.WarehouseCode = t.WarehouseCode and 
      t2.WarehouseName = t.WarehouseName and 
      t2.StorageAddress = t.StorageAddress 
    ) 
+0

я был в состоянии использовать второй запрос, и затем в выражении WHERE следует следующее выражение для условного ограничения (AND (t2.WarehouseCode = 'ALL' OR t2.WarehouseCode = t1.WarehouseCode)). – mrshickadance

0

Посмотрите в п EXCEPT, который работает подобно UNION

select col1, col2, col3 from yourtable 
EXCEPT 
select col1, col2, col3 from exceptions 
+0

Я не уверен, что я хочу, чтобы вернуть различные значения, и того, чтобы совпасть строки в запросе может потребоваться несколько дополнительных шагов для настройки общего – mrshickadance

0

там здесь есть две вещи. в первом случае вы объяснили, что таблица Exclude имеет такое же количество столбцов, что и в фактической таблице. Я предполагаю, что некоторые столбцы в этих таблицах будут «NULL able», а некоторые могут и не быть. поэтому во время исключения вам необходимо позаботиться об этом. Я вижу, что «Left Join» - хороший кандидат для использования здесь из-за причин производительности, а также вы можете выполнять MATCHING на выбранных столбцах только при необходимости. В вашем случае прямо сейчас кажется, что все столбцы должны совпадать, но подумайте в будущем, если Identity/datetime/timestamp, например столбец, добавленный в таблицу. см. Ниже код. если данные в этих таблицах имеют высокий уровень громкости, то NON-Clustered и/или индекс фильтра помогут вам улучшить производительность, но на более позднем этапе, если вы видите, что запросы просмотра медленны.

Для второй части, о которой вы упомянули, позже вы можете полностью исключить код местоположения и найти иерархическую зависимость. Я бы сказал, держите это отдельно, пока у вас нет точного требования.

DECLARE @AllData TABLE 
    (
     ID  INT   NOT NULL PRIMARY KEY 
     ,FName sysname  NOT NULL 
     ,LName sysname  NOT NULL 
     ,MName sysname  NULL 
    ) 

    DECLARE @ExcludeData TABLE 
    (
     ID  INT   NOT NULL PRIMARY KEY 
     ,FName sysname  NOT NULL 
     ,LName sysname  NOT NULL 
     ,MName sysname  NULL 
    ) 

    INSERT INTO @AllData(ID, FName, LName, MName) 
       SELECT 1,'Fname1','Lname1','MName1' 
    UNION ALL SELECT 2,'Fname2','Lname2',NULL 
    UNION ALL SELECT 3,'Fname3','Lname3','Mname3' 
    UNION ALL SELECT 4,'Fname4','Lname4',NULL 

    INSERT INTO @ExcludeData(ID, FName, LName, MName) 
       SELECT 1,'Fname1','Lname1','MName1' 
    UNION ALL SELECT 2,'Fname2','Lname2',NULL 

    SELECT a.ID,a.FName,a.LName,a.MName 
    FROM @AllData a 
    LEFT JOIN @ExcludeData b 
    ON 
     ((a.ID=b.ID) OR (a.id IS NULL AND b.id IS NULL)) 
     AND 
     ((a.FName=b.FName) OR (a.FName IS NULL AND b.FName IS NULL)) 
     AND 
     ((a.LName=b.LName) OR (a.LName IS NULL AND b.LName IS NULL)) 
     AND 
     ((a.MName=b.MName) OR (a.MName IS NULL AND b.MName IS NULL)) 
    WHERE 
     (b.ID IS NULL AND b.FName IS NULL AND b.LName IS NULL AND b.MName IS NULL) 
+0

Взяв пример, который вы дали. Скажем, в таблице исключений была запись, которая была [5, 'Fname3', 'Lnname3', 'ALL'].Предполагая, что «Все» означает, что они хотят исключить все комбинации Fname3 и Lname3 независимо от Mname. Как вы могли это объяснить, но при этом разрешаете другим строкам фильтровать столбец среднего имени, если они того пожелают? – mrshickadance

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