7

我想创建一个 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

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

任何指示或建议将不胜感激!

4

5 回答 5

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 
于 2012-05-16T21:23:51.330 回答
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

这是sqlfiddle的链接。

于 2012-05-16T20:59:24.743 回答
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)
于 2012-05-16T21:07:13.093 回答
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..)

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

于 2012-05-16T21:17:03.210 回答
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 小提琴版本

于 2012-05-16T21:52:14.210 回答