Как отфильтровать значения в таблице, но только если в ней есть записи? - PullRequest
1 голос
/ 18 января 2012

У меня есть таблица Tran с записями транзакций.

У меня есть две таблицы Parameters1 и Parameters2, которые используются для фильтрации результатов при выборе из таблицы Tran а-ля:

SELECT *  
FROM  
     Tran t JOIN  
     Parameters1 p1 ON T.code1 = p1.code1  
     Parameters2 p2 ON T.code2 = p2.code2  
WHERE p1.code1 is not null AND
      p2.code2 is not null

Иногда Parameters1 или Parameters2 пусто.

Я хочу, чтобы фильтрация происходила только в том случае, если в таблицах Parameters есть записи.Другими словами, если Parameters1 пусто, не используйте его для фильтрации, и наоборот.То же самое касается Parameters2.

Я в тупике.

Ответы [ 4 ]

3 голосов
/ 18 января 2012

Обычно вы делаете это, используя динамический SQL , так как кодирование условий динамического поиска с использованием статического SQL обычно хакерское. Если вас интересует такой подход, я настоятельно рекомендую страницу Эрланда Соммарскога по динамическому SQL для SQL Server 2005 . У него есть отличный пример с большим количеством примеров кода о том, как сделать именно то, что вы просите.

1. Настройка

Используете ли вы динамический или статический SQL, вы должны предварительно определить, какие фильтры применяются:

DECLARE @p1_filter BIT;
DECLARE @p2_filter BIT;

SET @p1_filter = 0;
SET @p2_filter = 0;

IF EXISTS (SELECT TOP (1) * FROM Parameters1)
BEGIN
   SET @p1_filter = 1;
END;

IF EXISTS (SELECT TOP (1) * FROM Parameters2)
BEGIN
   SET @p2_filter = 1;
END;

2.а. Динамический SQL

Если вы идете по динамическому маршруту SQL, вы должны сделать:

DECLARE @sql NVARCHAR(MAX);

SET @sql = 'SELECT * FROM Tran T ';

IF (@p1_filter = 1)
BEGIN
   SET @sql = @sql + 'INNER JOIN Parameters1 p1 ON T.code1 = p1.code1 ';
END;

IF (@p2_filter = 1)
BEGIN
   SET @sql = @sql + 'INNER JOIN Parameters2 p2 ON T.code2 = p2.code2 ';
END;

EXECUTE sp_executesql
   @statement = @sql
;

2.b.i. Статический SQL: подвыборы в предложении WHERE

В противном случае вы бы продолжили использовать этот уродливый (и, вероятно, плохо работающий) статический SQL:

SELECT *
FROM Tran T
WHERE 
   (
         T.code1 IN (SELECT code1 FROM Parameters1)
      OR (@p1_filter = 0)
   )
   AND
   (
         T.code2 IN (SELECT code2 FROM Parameters2)
      OR (@p2_filter = 0)
   )
;

Эрланд также представляет статические SQL-подходы, подобные этому, на на той же странице , о которой я говорил ранее. Вы можете найти лучший подход там.

2.b.ii. Статический SQL: LEFT OUTER JOIN

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

SELECT *
FROM 
                   Tran T
   LEFT OUTER JOIN Parameters1 p1
      ON T.code1 = p1.code1
   LEFT OUTER JOIN Parameters2 p2
      ON T.code2 = p2.code2
WHERE
       T.code1 = 
          CASE
             WHEN @p1_filter = 1
                THEN p1.code1
             ELSE T.code1
          END
   AND T.code2 =
          CASE
             WHEN @p2_filter = 1
                THEN p2.code2
             ELSE T.code2
          END
;
0 голосов
/ 18 января 2012

Я не уверен, что полностью понимаю, чего вы пытаетесь достичь.Вы хотите результатов, только если ОБА имеют результаты?Кроме того, я предполагаю, что p, на который ссылаются в ваших объединениях, должно быть псевдонимом таблицы для параметра 1 (p1) и параметра 2 (p2), а не только (p), как в вашем вопросе.

Если так, затем просто выберите t. * и LEFT JOIN в обеих таблицах параметров, таких как;

SELECT t.*  
FROM  
     Tran t 
     LEFT JOIN Parameters1 p1 ON T.code1 = p1.code1  
     LEFT JOIN Parameters2 p2 ON T.code2 = p2.code2  
WHERE p1.code1 is not null AND
      p2.code2 is not null
0 голосов
/ 18 января 2012

Как насчет exists

select * from Tran t

where exists(select 1 from Parameters1 p1 where t.code1 = p.code1)

and  exists(select 1 from Parameters2 p2 where t.code2 = p.code2)
0 голосов
/ 18 января 2012

Попробуйте использовать RIGHT JOIN:

SELECT * FROM Tran T  
RIGHT JOIN Parameters1 p1 ON T.code1 = p1.code1  
JOIN Parameters2 p2 ON T.code2 = p2.code2  
WHERE p1.code1 is not null AND p2.code2 is not null  
...