比较多个列,但只有那些具有有效值的列,如果all相等则创建y / n标志

时间:2012-05-16 20:54:02

标签: sql sql-server sql-server-2008

我想创建一个Y / N标志,其中Y表示给定行中每列中的每个有效值都相等,否则为N.我需要排除任何包含空值,空格或全零的列。假设:

CREATE TABLE z_test
(ID INT NOT NULL,
D1 VARCHAR(8)NULL,
D2 VARCHAR(8)NULL,
D3 VARCHAR(8)NULL,
D4 VARCHAR(8)NULL,
DFLAG CHAR(1)NULL)

INSERT INTO z_test VALUES (1,NULL,' ','000000','00000000',NULL)
INSERT INTO z_test VALUES (1,'20120101','0000','20120101','00000000',NULL)
INSERT INTO z_test VALUES (2,'20100101','20100101','20100101','20100101',NULL)
INSERT INTO z_test VALUES (2,'00000000','20090101','0','20090101',NULL)
INSERT INTO z_test VALUES (3,'00000000','20090101',NULL,'20120101',NULL)
INSERT INTO z_test VALUES (3,'20100101',' ',NULL,'20100101',NULL)

所需的输出(不包括D1到D4,但我不想丢弃它们)是:

ID       DFLAG
---------------
1        N
1        Y
2        Y
2        Y
3        N
3        Y

速度不是问题,因为这个查询不会经常运行,但它位于较大的表格上。

非常感谢任何指针或建议!!

5 个答案:

答案 0 :(得分:7)

SELECT ID, 
       CASE 
         WHEN C = 1 THEN 'Y' 
         ELSE 'N' 
       END AS DFLAG 
FROM   z_test 
       CROSS APPLY (SELECT COUNT(DISTINCT D) C 
                    FROM   (VALUES(D1), 
                                  (D2), 
                                  (D3), 
                                  (D4)) V(D) 
                    WHERE  LEN(D) > 0 /*Excludes blanks and NULLs*/
                         AND D LIKE '%[^0]%'/*Excludes ones with only zero*/) CA 

答案 1 :(得分:5)

这有效:

select case when
    (D1 is null OR D2 is null OR LEN(REPLACE(D1,'0',''))=0 OR LEN(REPLACE(D2,'0',''))=0 OR D1=D2)
AND (D1 is null OR D3 is null OR LEN(REPLACE(D1,'0',''))=0 OR LEN(REPLACE(D3,'0',''))=0 OR D1=D3)
AND (D1 is null OR D4 is null OR LEN(REPLACE(D1,'0',''))=0 OR LEN(REPLACE(D4,'0',''))=0 OR D1=D4)
AND (D2 is null OR D3 is null OR LEN(REPLACE(D2,'0',''))=0 OR LEN(REPLACE(D3,'0',''))=0 OR D2=D3)
AND (D2 is null OR D4 is null OR LEN(REPLACE(D2,'0',''))=0 OR LEN(REPLACE(D4,'0',''))=0 OR D2=D4)
AND (D3 is null OR D4 is null OR LEN(REPLACE(D3,'0',''))=0 OR LEN(REPLACE(D4,'0',''))=0 OR D3=D4)
AND (LEN(REPLACE(D1,'0','')) > 0
     OR LEN(REPLACE(D2,'0','')) > 0
     OR LEN(REPLACE(D3,'0','')) > 0
     OR LEN(REPLACE(D4,'0','')) > 0)
THEN 'Y' ELSE 'N' END
from z_test

以下是link到sqlfiddle。

答案 2 :(得分:1)

试试这个:

DECLARE @z_test table
(ID INT NOT NULL,
D1 VARCHAR(8)NULL,
D2 VARCHAR(8)NULL,
D3 VARCHAR(8)NULL,
D4 VARCHAR(8)NULL,
DFLAG CHAR(1)NULL)

INSERT INTO @z_test VALUES (1,NULL,' ','000000','00000000',NULL)
INSERT INTO @z_test VALUES (1,'20120101','0000','20120101','00000000',NULL)
INSERT INTO @z_test VALUES (2,'20100101','20100101','20100101','20100101',NULL)
INSERT INTO @z_test VALUES (2,'00000000','20090101','0','20090101',NULL)
INSERT INTO @z_test VALUES (3,'00000000','20090101',NULL,'20120101',NULL)
INSERT INTO @z_test VALUES (3,'20100101',' ',NULL,'20100101',NULL)

;WITH Fixed AS
(SELECT --converts columns with all zeros and any spaces to NULL
     ID
         ,NULLIF(NULLIF(D1,''),0) AS D1
         ,NULLIF(NULLIF(D2,''),0) AS D2
         ,NULLIF(NULLIF(D3,''),0) AS D3
         ,NULLIF(NULLIF(D4,''),0) AS D4
    FROM @z_test
)
SELECT --final result set
    ID,
    CASE 
        WHEN COALESCE(D1,D2,D3,D4) IS NULL THEN 'N' --all columns null
        WHEN (D1 IS NULL OR D1=COALESCE(D1,D2,D3,D4)) --all columns either null or the same
            AND (D2 IS NULL OR D2=COALESCE(D1,D2,D3,D4))
            AND (D3 IS NULL OR D3=COALESCE(D1,D2,D3,D4))
            AND (D4 IS NULL OR D4=COALESCE(D1,D2,D3,D4))
            THEN 'Y'
        ELSE 'N'
    END
    FROM Fixed

输出:

ID          
----------- ----
1           N
1           Y
2           Y
2           Y
3           N
3           Y

(6 row(s) affected)

答案 3 :(得分:0)

您可以为此创建一个功能。

create function fnRowValid(@d1 varchar, @d2 varchar...)
returns bit ------ 1 for true and 0 for false
begin

  declare table @validvalue (val varchar)

  if isdate(d1) = 0 and isdate(d1) = 0 and ...
    return 0

  if isdate(@d1)
    insert into @validvalue (val) values (@d1)
  if isdate(@d2)
    insert into @validvalue (val) values (@d2)
  if isdate(@d3)
    insert into @validvalue (val) values (@d3)
  ...


  if exists (select 1 from @validvalue)
    if (select count(distinct val) from @validvalue) = 1
      return 1

  return 0

end

然后你可以在更新语句中使用它......

update z_test
set dflag = dbo.fnRowValid(d1,d2,d3..)

请不要因此而激怒我...我没有明显地测试这段代码。这是第一个突然出现在我脑海中的解决方案......不是真正优雅但应该有效。我不肯定你可以在函数中使用表变量。抱歉丑陋的解决方案。

答案 4 :(得分:0)

With RnkSource As
  (
    Select Id, D1, D2, D3, D4, DFlag
      , Row_Number() Over ( Order By Id ) As RowNum
    From z_test
  )
  , Source As
  (
    Select RowNum, Id, 'D1' As Col, D1 As Val
    From RnkSource
    Union All
    Select RowNum, Id, 'D2', D2
    From RnkSource
    Union All
    Select RowNum, Id, 'D3', D3
    From RnkSource
    Union All
    Select RowNum, Id, 'D4', D4
    From RnkSource
  )
Select Id
  , Case When Count(*) = 4 Then 'Y' Else 'N' End As DFLAG
From Source As S
Where Len(Val) > 0
Group By RowNum, Id

SQL Fiddle version