我想创建一个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
速度不是问题,因为这个查询不会经常运行,但它位于较大的表格上。
非常感谢任何指针或建议!!
答案 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