Наиболее эффективный способ вернуть Y / N, если один или несколько столбцов содержат ненулевое значение? - PullRequest
5 голосов
/ 08 марта 2011

Какой самый краткий способ вернуть индикатор CHAR (1) Y / N, если один из n столбцов в строке содержит ненулевое значение?

Производительность важна,но не главное соображение, в данном случае.

Простой способ выглядит следующим образом:

SELECT      CASE WHEN (C.TerminatedDate IS NULL
                       AND C.SelfClosedDate IS NULL
                       AND ...)
                 THEN 'Y'
                 ELSE 'N' END AS 'OpenInd'

  FROM      Customers C

Интересно, есть ли лучший путь;известно о COALESCE ():

SELECT      CASE WHEN COALESCE (C.TerminatedDate, C.SelfClosedDate, ...) IS NULL
                 THEN 'Y'
                 ELSE 'N' END AS 'OpenInd'

  FROM      Customers C

Есть ли лучший способ?

Сервер базы данных - SQL Server 2008.

Ответы [ 6 ]

4 голосов
/ 08 марта 2011

Так как никто не предлагает это, и вопрос требует concise ..

Для тех же типов данных лучше использовать прямой COALESCE

coalesce(a,b,c,d) is not null

Если вы будете иметь дело с разными типами данных, попробуйте модифицированную COALESCE

coalesce(LEFT(a,1),LEFT(b,1),LEFT(c,1)) is not null

Пример:

create table abc (a int, b datetime, c varchar(max), d image)
insert into abc select 1, GETDATE(), '', null
insert into abc select 1, null, '', null
insert into abc select 1, null, '', 0x123123
insert into abc select null, null, '', 0x123123
insert into abc select null, GETDATE(), '', 0x123123
insert into abc select null, null, null, null
insert into abc select 88, GETDATE()+3, null, null
insert into abc select 88, GETDATE()+3, 'gdasdf', null
insert into abc select null, null, '222', 0x123123
insert into abc select null, null, 'abcdef', 0x123123

select *, case when coalesce(LEFT(a,1),LEFT(b,1),LEFT(c,1)) is not null then 'N' else 'Y' end
from abc

Если вы не используете экзотические типы, такие как VARCHAR (MAX) или IMAGE, вы можете использовать SQL_VARIANT с COALESCE

create table abc (a int, b datetime, c varchar(10), d image)
insert into abc select 1, GETDATE(), '', null
insert into abc select 1, null, '', null
insert into abc select 1, null, '', 0x123123
insert into abc select null, null, '', 0x123123
insert into abc select null, GETDATE(), '', 0x123123
insert into abc select null, null, null, null
insert into abc select 88, GETDATE()+3, null, null
insert into abc select 88, GETDATE()+3, 'gdasdf', null
insert into abc select null, null, '222', 0x123123
insert into abc select null, null, 'abcdef', 0x123123

select *, case when coalesce(convert(sql_variant,a),b,c) is not null then 'N' else 'Y' end
from abc
3 голосов
/ 08 марта 2011

Вот решение «вне коробки».Постоянный вычисляемый столбец.

CREATE TABLE [dbo].[Customer](
  [CustomerID] [int] IDENTITY(1,1) NOT NULL,
  [Date1] [datetime] NULL,
  [Date2] [datetime] NULL,
  [AllNulls]  AS (case when [date1] IS NULL AND [date2] IS NULL then 'Y' else 'N' end) PERSISTED NOT NULL,
 CONSTRAINT [PK_Cusomter] PRIMARY KEY CLUSTERED 
 (
    [CustomerID] ASC
 )
)
3 голосов
/ 08 марта 2011

Теоретически, вы должны получить преимущества короткого замыкания здесь, сразу же возвращаясь, когда любое значение не равно нулю

Select Case
        When C.TerminatedDate Is Not Null Then 'N'
        When C.SelfClosedDate Is Not Null Then 'N'
        ...
        Else 'Y'
        End

Тем не менее, я сомневаюсь, что между этим решением и вашими вышеупомянутыми решениями существует значительная разница в производительности (при условии, что вы можете использовать Coalesce).

2 голосов
/ 08 марта 2011

Без дополнительной информации первое (оператор case) является наиболее эффективным средством в MS SQL Server. (Хотя с теми же предположениями я лично вернул бы его как битовое значение и выполнил бы преобразование в Y / N, которое действительно является отображением или моделью представления.)

Теперь, если фильтрация будет выполняться неоднократно и по соображениям производительности целесообразно делать это на ядре базы данных, выполнение теста NULL в предложении where еще больше улучшит ситуацию. Если у вас их много, вы можете рассмотреть возможность их агрегирования при обновлении (через постоянный вычисляемый столбец, красиво предложенный другим ответчиком, хранимым процессом, моделью данных или небесным запретом на триггер).

1 голос
/ 09 марта 2011

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

CREATE TABLE coalescetest
(
id int identity(1,1) PRIMARY KEY,
bigvarchar1 varchar(max) NULL,
bigvarchar2 varchar(max) NULL,
bignvarchar1 Nvarchar(max) NULL,
bignvarchar2 Nvarchar(max) NULL
)

INSERT INTO coalescetest
SELECT TOP 100
     REPLICATE(CAST('A' AS VARCHAR(MAX)),12000),
     REPLICATE(CAST('A' AS VARCHAR(MAX)),12000),
     REPLICATE(CAST('A' AS NVARCHAR(MAX)),12000),
     REPLICATE(CAST('A' AS NVARCHAR(MAX)),12000)   
FROM master..spt_values             

SET STATISTICS IO ON    

SELECT      id, CASE WHEN COALESCE (bigvarchar1,bigvarchar2,bignvarchar1,bignvarchar2) IS NULL
                 THEN 'Y'
                 ELSE 'N' END AS Result

FROM coalescetest

Дает

Таблица 'coalescetest',Сканирование 1, логическое чтение 5, физическое чтение 0, чтение с опережением 0, логическое чтение lob 400 , физическое чтение за 0, чтение с опережением чтение 300 .

SELECT      CASE WHEN (bigvarchar1 IS NULL
                       AND bigvarchar2 IS NULL
                       AND bignvarchar1 IS NULL
                       AND bignvarchar2 IS NULL)
                 THEN 'Y'
                 ELSE 'N' END AS Result
  FROM     coalescetest

Дает

Таблица 'coalescetest'.Сканирование 1, логическое чтение 5, физическое чтение 0, чтение с опережением 0, чтение логического объекта lob 0 , физическое чтение с чтения 0, чтение с опережением чтения 0 .

1 голос
/ 08 марта 2011

Если все столбцы имеют дату и время, это работает, если только общее переполнение.Примечание ноль = 01 января 1900 года, поэтому до 31 декабря 9999

NULL, добавленный к любому другому выражению, дает большой запас NULL

SELECT
    CASE
         WHEN C.TerminatedDate + C.SelfClosedDate + C.OtherDate + .. IS NULL THEN
                 THEN 'Y'
                 ELSE 'N'
         END AS 'OpenInd'

  FROM      Customers C
...