当列名基于变量结果时,如何 return 来自多个列的值
How do I return values from multiple columns when the column names are based on a variable result
我在 SQL 服务器中有一个 table,它在单独的列中列出旅程中不同阶段的日期。我还有一个专栏,显示当前旅程的阶段。
对于每个阶段,都有一列 header 表示阶段名称,列中将是与该阶段关联的日期。
我想要 运行 一个 SELECT
语句,它将 'current stage' 与列名和 return 相关联的日期相匹配。
例如,这可能是 table(实际的 table 有 40 个阶段 - 不要问!):
record id | current stage | met client | contract agreed | service completed | on hold**
11111S | met client | 2019-01-02 | NULL | NULL | NULL
22222P | contract agreed | 2019-01-02 | 2019-01-20 | NULL | NULL
33333A | on hold | 2019-01-02 | 2019-01-20 | NULL | 2019-02-10
44444C | service completed | 2019-01-02 | 2019-01-20 | 2019-03-01 | 2019-02-10
我想写一个 SELECT
语句来显示:
record_id | current_stage | date_of_current_stage
11111S | met client | 2019-01-02 |
22222P | contract agreed | 2019-01-20 |
33333A | on hold | 2019-02-10 |
44444C | service completed | 2019-03-01 |
您可以使用动态 SQL 实现它,方法如下(将 #X
替换为您的实际 table):
CREATE TABLE #X
(
[record id] int
, [current stage] varchar(255)
, [met client] date
, [contract agreed] date
, [service completed] date
, [on hold] date
)
INSERT INTO #X VALUES (11111, 'met client', '2019-01-02', NULL, NULL, NULL)
INSERT INTO #X VALUES (22222, 'contract agreed', '2019-01-02', '2019-01-20', NULL, NULL)
INSERT INTO #X VALUES (33333, 'on hold', '2019-01-02', '2019-01-20', NULL, '2019-02-10')
INSERT INTO #X VALUES (44444, 'service completed', '2019-01-02', '2019-01-20', '2019-03-01', '2019-02-10')
DECLARE @y table
(
[record id] int
, [statement] varchar(1000)
)
INSERT INTO @y
(
[record id]
, [statement]
)
SELECT
[record id]
, 'SELECT [record id], [current stage], ' + QUOTENAME([current stage]) + ' [date of current stage] FROM #X WHERE [record id] = ' + CAST([record id] AS varchar(20)) [statement]
FROM #X
DECLARE
@CurrentRecord int
, @SQL nvarchar(max) = ''
WHILE EXISTS (SELECT * FROM @y)
BEGIN
SELECT @CurrentRecord = MIN([record id]) FROM @y
IF (SELECT COUNT(*) FROM @y) = 1
SET @SQL = @SQL + (SELECT [statement] FROM @y WHERE [record id] = @CurrentRecord)
ELSE
SET @SQL = @SQL + (SELECT [statement] + ' UNION ALL ' FROM @y WHERE [record id] = @CurrentRecord)
DELETE @y
WHERE [record id] = @CurrentRecord
END
EXEC sp_executesql @SQL
DROP TABLE #X
您可以使用 UNION ALL
的子查询
select record_id,
current_stage,
max(met_client) as date_of_current_stage
from (
select record_id, current_stage, met_client from test union all
select record_id, current_stage, contract_agreed from test union all
select record_id, current_stage, service_completed from test union all
select record_id, current_stage, on_hold from test) t group by record_id, current_stage
如果你想让它动态,那么你可以使用动态 UNPIVOT
,如下所示
DECLARE @col VARCHAR(1000)
DECLARE @sql VARCHAR(2000)
SELECT @col = COALESCE(@col + ', ','') + QUOTENAME([current stage])
FROM #Test
SELECT @col
SET @sql = '
SELECT t.[record id], [current stage], date_of_current_stage
FROM #Test t
LEFT JOIN (SELECT [record id], Stage, Dates
FROM (
SELECT * FROM #Test
) p
UNPIVOT (
Dates For Stage IN (' + @col + ')
) pv
) s ON t.[record id] = s.[record id]
AND t.[current stage] = s.Stage '
EXEC(@sql)
您似乎只需要匹配 current_stage 列的相应列值。您可以尝试以下查询 -
SELECT record_id
,current_stage
,CASE WHEN current_stage = 'met client' THEN [met client]
WHEN current_stage = 'contract agreed' THEN [contract agreed]
WHEN current_stage = 'service completed' THEN [service completed]
WHEN current_stage = 'on hold' THEN [on hold] END date_of_current_stage
FROM YOUR_TABLE;
如果这有其他逻辑,this文章可能对您有所帮助。
使用UNPIVOT
,这样current stage
值必须满足列名:
CREATE TABLE #Test (
[record id] INT,
[current stage] VARCHAR(32),
[met client] DATE,
[contract agreed] DATE,
[service completed] DATE,
[on hold] DATE
)
INSERT #Test ([record id],
[current stage],
[met client],
[contract agreed],
[service completed],
[on hold])
VALUES
(11111, 'met client', '2019-01-02', NULL, NULL, NULL),
(22222, 'contract agreed', '2019-01-02', '2019-01-20', NULL, NULL),
(33333, 'on hold', '2019-01-02', '2019-01-20', NULL, '2019-02-10'),
(44444, 'service completed', '2019-01-02', '2019-01-20', '2019-03-01', '2019-02-10')
DECLARE @SQL NVARCHAR(MAX),
@ColumnsList NVARCHAR(MAX) = ''
SELECT @ColumnsList = STUFF (
(
SELECT DISTINCT ',' + QUOTENAME([current stage])
FROM #Test
FOR XML PATH('')
),
1, 1, '')
SET @SQL =
'
SELECT t.[record id], [current stage], Dates
FROM #Test t
LEFT JOIN (
SELECT [record id], Stage, Dates
FROM (
SELECT [record id],' + @ColumnsList + '
FROM #Test
) p
UNPIVOT (
Dates For Stage IN (' + @ColumnsList + ')
) pv
) s ON t.[record id] = s.[record id]
AND t.[current stage] = s.Stage
'
EXEC sp_executesql @SQL
已更新 以避免必须手动指定每个阶段
以下使用动态 UNPIVOT
操作的查询将完成工作:
CREATE TABLE #yourTable ( [record id] INT,[current stage] VARCHAR(255), [met client] DATE, [contract agreed] DATE, [service completed] DATE, [on hold] DATE)
INSERT INTO #yourTable VALUES
(11111, 'met client', '2019-01-02', NULL, NULL, NULL),
(22222, 'contract agreed', '2019-01-02', '2019-01-20', NULL, NULL),
(33333, 'on hold', '2019-01-02', '2019-01-20', NULL, '2019-02-10'),
(44444, 'service completed', '2019-01-02', '2019-01-20', '2019-03-01', '2019-02-10')
DECLARE @col NVARCHAR(MAX) = '';
SELECT @col += ',' + QUOTENAME([current stage]) FROM #yourTable
SET @col = STUFF(@col,1,1,'')
EXEC ( 'SELECT unpiv.[record id], unpiv.[current stage], [Date] AS [Date_of_current_stage] FROM #yourTable UNPIVOT ([Date] FOR [Stage] IN ('+@col+') ) unpiv WHERE [current stage] = [Stage]')
我在 SQL 服务器中有一个 table,它在单独的列中列出旅程中不同阶段的日期。我还有一个专栏,显示当前旅程的阶段。
对于每个阶段,都有一列 header 表示阶段名称,列中将是与该阶段关联的日期。
我想要 运行 一个 SELECT
语句,它将 'current stage' 与列名和 return 相关联的日期相匹配。
例如,这可能是 table(实际的 table 有 40 个阶段 - 不要问!):
record id | current stage | met client | contract agreed | service completed | on hold**
11111S | met client | 2019-01-02 | NULL | NULL | NULL
22222P | contract agreed | 2019-01-02 | 2019-01-20 | NULL | NULL
33333A | on hold | 2019-01-02 | 2019-01-20 | NULL | 2019-02-10
44444C | service completed | 2019-01-02 | 2019-01-20 | 2019-03-01 | 2019-02-10
我想写一个 SELECT
语句来显示:
record_id | current_stage | date_of_current_stage
11111S | met client | 2019-01-02 |
22222P | contract agreed | 2019-01-20 |
33333A | on hold | 2019-02-10 |
44444C | service completed | 2019-03-01 |
您可以使用动态 SQL 实现它,方法如下(将 #X
替换为您的实际 table):
CREATE TABLE #X
(
[record id] int
, [current stage] varchar(255)
, [met client] date
, [contract agreed] date
, [service completed] date
, [on hold] date
)
INSERT INTO #X VALUES (11111, 'met client', '2019-01-02', NULL, NULL, NULL)
INSERT INTO #X VALUES (22222, 'contract agreed', '2019-01-02', '2019-01-20', NULL, NULL)
INSERT INTO #X VALUES (33333, 'on hold', '2019-01-02', '2019-01-20', NULL, '2019-02-10')
INSERT INTO #X VALUES (44444, 'service completed', '2019-01-02', '2019-01-20', '2019-03-01', '2019-02-10')
DECLARE @y table
(
[record id] int
, [statement] varchar(1000)
)
INSERT INTO @y
(
[record id]
, [statement]
)
SELECT
[record id]
, 'SELECT [record id], [current stage], ' + QUOTENAME([current stage]) + ' [date of current stage] FROM #X WHERE [record id] = ' + CAST([record id] AS varchar(20)) [statement]
FROM #X
DECLARE
@CurrentRecord int
, @SQL nvarchar(max) = ''
WHILE EXISTS (SELECT * FROM @y)
BEGIN
SELECT @CurrentRecord = MIN([record id]) FROM @y
IF (SELECT COUNT(*) FROM @y) = 1
SET @SQL = @SQL + (SELECT [statement] FROM @y WHERE [record id] = @CurrentRecord)
ELSE
SET @SQL = @SQL + (SELECT [statement] + ' UNION ALL ' FROM @y WHERE [record id] = @CurrentRecord)
DELETE @y
WHERE [record id] = @CurrentRecord
END
EXEC sp_executesql @SQL
DROP TABLE #X
您可以使用 UNION ALL
select record_id,
current_stage,
max(met_client) as date_of_current_stage
from (
select record_id, current_stage, met_client from test union all
select record_id, current_stage, contract_agreed from test union all
select record_id, current_stage, service_completed from test union all
select record_id, current_stage, on_hold from test) t group by record_id, current_stage
如果你想让它动态,那么你可以使用动态 UNPIVOT
,如下所示
DECLARE @col VARCHAR(1000)
DECLARE @sql VARCHAR(2000)
SELECT @col = COALESCE(@col + ', ','') + QUOTENAME([current stage])
FROM #Test
SELECT @col
SET @sql = '
SELECT t.[record id], [current stage], date_of_current_stage
FROM #Test t
LEFT JOIN (SELECT [record id], Stage, Dates
FROM (
SELECT * FROM #Test
) p
UNPIVOT (
Dates For Stage IN (' + @col + ')
) pv
) s ON t.[record id] = s.[record id]
AND t.[current stage] = s.Stage '
EXEC(@sql)
您似乎只需要匹配 current_stage 列的相应列值。您可以尝试以下查询 -
SELECT record_id
,current_stage
,CASE WHEN current_stage = 'met client' THEN [met client]
WHEN current_stage = 'contract agreed' THEN [contract agreed]
WHEN current_stage = 'service completed' THEN [service completed]
WHEN current_stage = 'on hold' THEN [on hold] END date_of_current_stage
FROM YOUR_TABLE;
如果这有其他逻辑,this文章可能对您有所帮助。
使用UNPIVOT
,这样current stage
值必须满足列名:
CREATE TABLE #Test (
[record id] INT,
[current stage] VARCHAR(32),
[met client] DATE,
[contract agreed] DATE,
[service completed] DATE,
[on hold] DATE
)
INSERT #Test ([record id],
[current stage],
[met client],
[contract agreed],
[service completed],
[on hold])
VALUES
(11111, 'met client', '2019-01-02', NULL, NULL, NULL),
(22222, 'contract agreed', '2019-01-02', '2019-01-20', NULL, NULL),
(33333, 'on hold', '2019-01-02', '2019-01-20', NULL, '2019-02-10'),
(44444, 'service completed', '2019-01-02', '2019-01-20', '2019-03-01', '2019-02-10')
DECLARE @SQL NVARCHAR(MAX),
@ColumnsList NVARCHAR(MAX) = ''
SELECT @ColumnsList = STUFF (
(
SELECT DISTINCT ',' + QUOTENAME([current stage])
FROM #Test
FOR XML PATH('')
),
1, 1, '')
SET @SQL =
'
SELECT t.[record id], [current stage], Dates
FROM #Test t
LEFT JOIN (
SELECT [record id], Stage, Dates
FROM (
SELECT [record id],' + @ColumnsList + '
FROM #Test
) p
UNPIVOT (
Dates For Stage IN (' + @ColumnsList + ')
) pv
) s ON t.[record id] = s.[record id]
AND t.[current stage] = s.Stage
'
EXEC sp_executesql @SQL
已更新 以避免必须手动指定每个阶段
以下使用动态 UNPIVOT
操作的查询将完成工作:
CREATE TABLE #yourTable ( [record id] INT,[current stage] VARCHAR(255), [met client] DATE, [contract agreed] DATE, [service completed] DATE, [on hold] DATE)
INSERT INTO #yourTable VALUES
(11111, 'met client', '2019-01-02', NULL, NULL, NULL),
(22222, 'contract agreed', '2019-01-02', '2019-01-20', NULL, NULL),
(33333, 'on hold', '2019-01-02', '2019-01-20', NULL, '2019-02-10'),
(44444, 'service completed', '2019-01-02', '2019-01-20', '2019-03-01', '2019-02-10')
DECLARE @col NVARCHAR(MAX) = '';
SELECT @col += ',' + QUOTENAME([current stage]) FROM #yourTable
SET @col = STUFF(@col,1,1,'')
EXEC ( 'SELECT unpiv.[record id], unpiv.[current stage], [Date] AS [Date_of_current_stage] FROM #yourTable UNPIVOT ([Date] FOR [Stage] IN ('+@col+') ) unpiv WHERE [current stage] = [Stage]')