当值基于另一列中的值时,如何将多个SELECT语句压缩为一个?

2020-02-22 sql sql-server tsql

XML从前端发送到存储过程,该过程将其解析为具有两列的临时表:

 | DataName | DataValue |
1| blahblah | datadata  |
2|    ...   |    ...    |
3|    ...   |    ...    |
4|    ...   |    ...    |

从这个临时表中,我将基于DataName列中的字符串将DataValue列中的值设置为变量。例如:

SELECT @blahblah= IsNull(DataValue,0)
        FROM #XMLTempTable
        WHERE DataName = 'blahblah'

SELECT @userid = IsNull(DataValue,0)
        FROM #XMLTempTable
        WHERE DataName = 'userid'

SELECT @value = IsNull(DataValue,0)
        FROM #XMLTempTable
        WHERE DataName = 'value'

有没有一种更好的方法可以从临时表中选择值,而不是像我现在每次选择一个?

Answers

您可以使用CASE WHEN .. END来实现

SELECT @blahblah = CASE WHEN  DataName = 'blahblah' THEN IsNull(DataValue,0) ELSE 0 END, 
       @userid = CASE WHEN  DataName = 'userid' THEN IsNull(DataValue,0) ELSE 0 END, 
       @value = CASE WHEN  DataName = 'value' THEN IsNull(DataValue,0) ELSE 0 END
FROM #XMLTempTable
WHERE DataName in ('blahblah', 'userid', 'value')

如果您有权创建函数,则还可以考虑以使代码一致,可重用和可共享的方式实现逻辑。对于需要频繁执行通用数据清除逻辑的数据分析人员或部门DBA,此方法非常方便。

测试数据集

use [testdb];
if OBJECT_ID('testdb..test') is not null
    drop table testdb..test;

create table test (
    DataName varchar(50),
    DataValue varchar(50),
);

insert into test (DataName, DataValue)
values ('name1', NULL),('name2', NULL),('name3', NULL);

select * from test;
GO

将您的逻辑放入可重用的函数中

if OBJECT_ID('testdb.dbo.myfunc', 'FN') is not null
    drop function myfunc;
GO

CREATE FUNCTION dbo.myfunc(@param varchar(100))  
RETURNS varchar(100)
AS
BEGIN  
    -- implement your logic here
    declare @ret varchar(max);

    if @param = 'name1'
        set @ret = @param + '_logic1';
    else if @param = 'name2'
        set @ret = @param + '_logic2';
    else if @param = 'name3'
        set @ret = @param + '_logic3';

    return @ret;
END
GO

执行

update A
    set A.DataValue = dbo.myfunc(A.DataName)
    from test as A;

select * from test;
-- DataName  DataValue
-- name1     name1_logic1
-- name2     name2_logic2
-- name3     name3_logic3

如果您尝试将这些键/值对“透视”为更有意义的行,那么这可能会对您有所帮助。但是请注意,假设sql表中的任何行顺序都是一个坏主意,尽管如此,以下内容仍是这样。

CREATE TABLE #XMLTempTable(
   ID INT  NOT NULL IDENTITY PRIMARY KEY
  ,DataName  VARCHAR(20) NOT NULL
  ,DataValue VARCHAR(20) NOT NULL
);
INSERT INTO #XMLTempTable(DataName,DataValue) VALUES ('blahblah','blah-1');
INSERT INTO #XMLTempTable(DataName,DataValue) VALUES ('userid','user-1');
INSERT INTO #XMLTempTable(DataName,DataValue) VALUES ('value','value-1');
INSERT INTO #XMLTempTable(DataName,DataValue) VALUES ('blahblah','blah-2');
INSERT INTO #XMLTempTable(DataName,DataValue) VALUES ('userid','user-2');
INSERT INTO #XMLTempTable(DataName,DataValue) VALUES ('value','value-2');
GO
 6行受影响
SELECT 
  id
, blahblah = CASE WHEN  DataName = 'blahblah' THEN datavalue END
, userid = CASE WHEN  DataName = 'userid' THEN DataValue END
, value = CASE WHEN  DataName = 'value' THEN DataValue END
FROM #XMLTempTable
WHERE DataName in ('blahblah', 'userid', 'value')
GO
 id |等等用户名|值
 -:| :------- | :----- | :------ 
 1 | blah-1 |  | 空值 
 2 |  |用户1 | 空值 
 3 |  |  |值1 
 4 | blah-2 |  | 空值 
 5 |  |用户2 | 空值 
 6 |  |  |值2 
SELECT 
  (id + 2) / 3 as rowno
, max(CASE WHEN  DataName = 'blahblah' THEN datavalue END) as blahblah
, max(CASE WHEN  DataName = 'userid' THEN DataValue END) as userid
, max(CASE WHEN  DataName = 'value' THEN DataValue END) as datavalue
FROM #XMLTempTable
WHERE DataName in ('blahblah', 'userid', 'value')
GROUP BY
  (id + 2) / 3
GO
行号|等等用户名|数据值
 ----:| :------- | :----- | :-------- 
 1 | blah-1 |用户1 |值1 
 2 | blah-2 |用户2 |值2 

db <> 在这里拨弄

Related