我有一个查找表,其中包含很多带有值的列。
如何使用Microsoft SQL Server从输入中获得此输出?
(基本上选择列名称,其中Date = MAX()AND ColX到ColZ值= <5.4)。
输入
ID Date ColX ColY ColZ ----------------------------------------------------- 79185673 2018-11-28 00:00:00 3 5 7 79185673 2018-12-02 00:00:00 2 4 6 79185673 2018-12-04 00:00:00 4 5 6
输出
ID Date Column -------------------------------------- 79185673 2018-12-04 00:00:00 ColY
答案 0 :(得分:2)
这是您要找的吗
SELECT TOP 1 *,
CASE WHEN 5.4 > ColZ
THEN 'ColZ'
WHEN 5.4 > ColY
THEN 'ColY'
WHEN 5.4 > ColX
THEN 'ColX'
END [Column]
FROM T
ORDER BY [Date] DESC;
答案 1 :(得分:1)
DDL中固定的列名称是元数据,而不是存储在行中的值。您可以通过从information_schema.columns
表中进行选择来查看列名。但是,要实现所请求的逻辑,可以使用SQL中的CASE
语句来完成。
假设表名称为table1
,请尝试以下查询:
declare @compare_value decimal(2,1);
@compare_value = 5.4;
select
t.ID,
t.Date,
case when t.colX <= @compare_value then
case when t.ColY <= @compare_value then
case when t.ColZ <= @compare_value then
'ColZ'
else
'ColY'
end
else
'ColY'
end
else
'ColX'
end as "Column"
from table1 t
where t.date = (
select max(t1.date)
from table1 t1
where t1.ID = t.ID
);
请注意:该代码已嵌套到3个级别,并且需要为每列嵌套(可能是150个级别)!那是一些严重的spagetti代码。它会工作,但看起来会很混乱。如果数据量巨大,那么性能也可能成为问题,因为SQL对于复杂的逻辑并不是真正有用。 使用SQL仅选择所需的数据并使用存储过程,或者通过ODBC连接(例如.NET或Python)提供数据,会更好。然后在那里进行复杂的逻辑处理。
答案 2 :(得分:1)
我们将逐步进行。这是数据设置:
DECLARE @table TABLE
(
ID INTEGER NOT NULL
,Date DATETIME NOT NULL
,ColX INTEGER NOT NULL
,ColY INTEGER NOT NULL
,ColZ INTEGER NOT NULL
);
INSERT INTO @table
(ID,Date,ColX,ColY,ColZ)
VALUES
(79185673, '2018-11-28T00:00:00', 3, 5, 7);
INSERT INTO @table
(ID,Date,ColX,ColY,ColZ)
VALUES
(79185673, '2018-12-02T00:00:00', 2, 4, 6);
INSERT INTO @table
(ID,Date,ColX,ColY,ColZ)
VALUES
(79185673, '2018-12-04T00:00:00', 4, 5, 6);
首先,我们将找到具有最大日期的记录。
SELECT TOP (1)
*
FROM
@table
ORDER BY
[Date] DESC
+----------+-------------------------+------+------+------+
| ID | Date | ColX | ColY | ColZ |
+----------+-------------------------+------+------+------+
| 79185673 | 2018-12-04 00:00:00.000 | 4 | 5 | 6 |
+----------+-------------------------+------+------+------+
因此形成了我们的基本数据集。从这里开始,我们要UNPIVOT
将所有列值都放入一个列中。您必须在UNPIVOT
中键入所有其他列名称,但是您可能只需使用默认的SELECT TOP N ROWS
查询并复制和粘贴,就可以让SSMS为您执行一些脚本编制工作从那里开始的列名。
SELECT
*
FROM
(
SELECT
TOP (1)
*
FROM
@table
ORDER BY
[Date] DESC
) AS d
UNPIVOT
(
Nums
FOR ColName IN (ColX, ColY, ColZ)
) AS p
+----------+-------------------------+------+---------+
| ID | Date | Nums | ColName |
+----------+-------------------------+------+---------+
| 79185673 | 2018-12-04 00:00:00.000 | 4 | ColX |
| 79185673 | 2018-12-04 00:00:00.000 | 5 | ColY |
| 79185673 | 2018-12-04 00:00:00.000 | 6 | ColZ |
+----------+-------------------------+------+---------+
根据注释,列中的数字始终在增加,因此我们可以安全地对其进行排序并保持原始顺序。但是我们只关心小于目标数(在此示例中为5.4)的数字。这就是我们的WHERE
子句。而且我们希望最大的数字小于5.4,因此我们将使用降序ORDER BY
子句。我们只需要一个值,因此最终结果中只需要TOP (1)
。
DECLARE @target DECIMAL(5,1) = 5.4;
SELECT TOP (1)
*
FROM
(
SELECT
TOP (1)
*
FROM
@table
ORDER BY
[Date] DESC
) AS d
UNPIVOT
(
Nums
FOR ColName IN (ColX, ColY, ColZ)
) AS p
WHERE
p.Nums < @target
ORDER BY
p.Nums DESC;
+----------+-------------------------+------+---------+
| ID | Date | Nums | ColName |
+----------+-------------------------+------+---------+
| 79185673 | 2018-12-04 00:00:00.000 | 5 | ColY |
+----------+-------------------------+------+---------+
答案 3 :(得分:0)
根据他们的评论,我怀疑这就是OP的要求,但根据他们的问题,答案是:
DECLARE @MyValue decimal(2,1) = 5.4
WITH CTE AS(
SELECT ID,
[Date],
ColX,Coly,ColZ,
ROW_NUMBER() OVER (ORDER BY [Date] DESC) AS RN --PARTITION BY ID?
FROM TheirTable)
SELECT ID,
[Date],
CASE WHEN ColZ < @MyValue THEN 'ColZ'
WHEN ColY < @MyValue THEN 'ColY'
WHEN ColX < @MyValue THEN 'ColX'
END AS [Column]
FROM CTE
WHERE RN = 1;
他们的评论(在问题下)有点领先,但是在更新他们的问题后,他们仍然只有5列,所以我要假设他们实际上有5列。也没有真正的确切解释,这是我的“最佳猜测”。