有没有更快的方法来查找 COLUMN 的顺序?
Is there a faster way to find the order of a COLUMN?
我的 SQL 服务器 table 看起来像这样
ID a_Toyota a_Mazda a_Nissan a_Kia a_Honda a_Subaru SoldCar CarOrder
1 8000 7000 6200 8500 6500 7000 Mazda NULL
2 4000 5000 4500 3500 3500 5000 Mazda NULL
3 5400 5000 4500 5500 5500 4600 Mazda NULL
4 5600 6300 7500 8200 6500 7300 Mazda NULL
5 8500 7400 7400 6500 9500 9000 Mazda NULL
6 9900 8000 9900 7300 8100 8000 Mazda NULL
我想更新 CarOrder 字段,所以它具有已售出汽车的价格与其他汽车价格相比的顺序。
因此,对于 ID 1 的汽车价格,如 a_Kia (8500) 是 1st 和 a_Toyota (8000) 是 2nd 和 a_Mazda & a_Subaru (7000) 是3rd and a_Honda (6500) is 5th and a_Nissan (6200) 是 第 6
售出的汽车是马自达,排名第三,所以 table 应该如下
ID a_Toyota a_Mazda a_Nissan a_Kia a_Honda a_Subaru SoldCar CarOrder
1 8000 7000 6200 8500 6500 7000 Mazda 3
2 4000 5000 4500 3500 3500 5000 Subaru 1
3 5400 5000 4500 5500 5500 4600 Toyota 3
4 5600 6300 7500 8200 6500 7300 Honda 4
5 8500 7400 7400 6500 9500 9000 Honda 1
6 9900 8000 9900 7300 8100 8000 Honda 3
我可以找到带有大 CASE 语句的订单
UPDATE mytable
SET CarOrder =
CASE WHEN SoldCar = 'Toyota' AND a_Toyota>=a_Mazda AND a_Toyota>=a_Nissan AND ... AND a_Toyota>=a_Subaru THEN 1
CASE WHEN SoldCar = 'Toyota' AND a_Toyota<a_Mazda AND a_Toyota>=a_Nissan AND ... AND a_Toyota>=a_Subaru THEN 2
CASE WHEN SoldCar = 'Toyota' AND a_Toyota>=a_Mazda AND a_Toyota<a_Nissan AND ... AND a_Toyota>=a_Subaru THEN 2
.
.
.
CASE WHEN SoldCar = 'Toyota' AND a_Toyota>=a_Mazda AND a_Toyota>=a_Nissan AND ... AND a_Toyota<a_Subaru THEN 2
.
.
.
CASE WHEN SoldCar = 'Toyota' AND a_Toyota<a_Mazda AND a_Toyota<a_Nissan AND ... AND a_Toyota>=a_Subaru THEN 3
..
..
..
但这将是一个巨大的案例陈述。
不知道有人有更简单的方法吗?
假设 table 结构类似于以下内容:
CREATE TABLE tempdb..cars
(
ID INT NOT NULL,
a_Toyota INT NOT NULL,
a_Mazda INT NOT NULL,
a_Nissan INT NOT NULL,
a_Kia INT NOT NULL,
a_Honda INT NOT NULL,
a_Subaru INT NOT NULL,
SoldCar VARCHAR(100) NOT NULL,
CarOrder INT NULL
);
一种方法是利用 APPLY operator. Something like the following should give you a resultset from a table structure like above, assuming the use of CROSS APPLY and a non-dense RANK (vs a DENSE RANK) 以及降序来确定您的顺序:
SELECT c.ID, c.SoldCar, o.ord AS CarOrder
FROM tempdb..cars c
CROSS APPLY
(
SELECT t.ord
FROM (
SELECT r.car, RANK() OVER (ORDER BY r.qty DESC) AS ord
FROM (
SELECT c.a_Toyota AS qty, 'Toyota' AS car
UNION ALL
SELECT c.a_Mazda AS qty, 'Mazda' AS car
UNION ALL
SELECT c.a_Nissan AS qty, 'Nissan' AS car
UNION ALL
SELECT c.a_Kia AS qty, 'Kia' AS car
UNION ALL
SELECT c.a_Honda AS qty, 'Honda' AS car
UNION ALL
SELECT c.a_Subaru AS qty, 'Subaru' AS car
) r
) t
WHERE t.car = c.SoldCar
) o
table 结构需要从一开始就转向它应该有的东西,这将有助于轻松确定正确的顺序并满足任何数量的品牌。
您可以使用交叉应用和 row_number 将每个值与其序号位置相匹配,使用 updatable CTE 更新基础 table。
with cars as (
select * from t
cross apply (
select case soldcar
when 'Toyota' then a_Toyota
when 'Mazda' then a_Mazda
when 'Nissan' then a_Nissan
when 'Honda' then a_Honda
when 'Subaru' then a_Subaru
end
)s(SoldValue)
cross apply (
select rank() over (order by v desc) co, v
from (values(a_toyota),(a_mazda),(a_nissan),(a_kia),(a_honda),(a_subaru))v(v)
)c
where SoldValue=v
)
update cars set carOrder=co
又一个基于XQuery的方法。
对于ID=2的行,Subary和Mazda打成平手。他们都有5000的价值。
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (
ID INT IDENTITY(1,1) PRIMARY KEY,
a_Toyota INT,
a_Mazda INT,
a_Nissan INT,
a_Kia INT,
a_Honda INT,
a_Subaru INT,
SoldCar VARCHAR(20)
);
INSERT INTO @tbl
(
a_Toyota,
a_Mazda,
a_Nissan,
a_Kia,
a_Honda,
a_Subaru,
SoldCar
) VALUES
(8000, 7000, 6200, 8500, 6500, 7000, 'Mazda'),
(4000, 5000, 4500, 3500, 3500, 5000, 'Subaru'),
(5400, 5000, 4500, 5500, 5500, 4600, 'Toyota'),
(5600, 6300, 7500, 8200, 6500, 7300, 'Honda'),
(8500, 7400, 7400, 6500, 9500, 9000, 'Honda'),
(9900, 8000, 9900, 7300, 8100, 8000, 'Honda');
-- DDL and sample data population, end
SELECT t.*, CarOrder
FROM @tbl AS t
CROSS APPLY (SELECT a_Toyota, a_Mazda, a_Nissan,
a_Kia, a_Honda, a_Subaru, SoldCar
FOR XML PATH(''), TYPE, ROOT('root')) AS t1(c)
CROSS APPLY (SELECT c.query('<root>
{
for $r in /root/*
order by data($r) descending
return <r>
<make>{local-name($r)}</make>
<salePrice>{data($r)}</salePrice>
</r>
}
</root>').query('
let $soldcar := sql:column("SoldCar")
for $r in /root/r[contains((make/text())[1], $soldcar)]
let $pos := count(root/*[. << $r])
return $pos').value('.','INT')
) AS t2(CarOrder);
输出
+----+----------+---------+----------+-------+---------+----------+---------+----------+
| ID | a_Toyota | a_Mazda | a_Nissan | a_Kia | a_Honda | a_Subaru | SoldCar | CarOrder |
+----+----------+---------+----------+-------+---------+----------+---------+----------+
| 1 | 8000 | 7000 | 6200 | 8500 | 6500 | 7000 | Mazda | 3 |
| 2 | 4000 | 5000 | 4500 | 3500 | 3500 | 5000 | Subaru | 2 |
| 3 | 5400 | 5000 | 4500 | 5500 | 5500 | 4600 | Toyota | 3 |
| 4 | 5600 | 6300 | 7500 | 8200 | 6500 | 7300 | Honda | 4 |
| 5 | 8500 | 7400 | 7400 | 6500 | 9500 | 9000 | Honda | 1 |
| 6 | 9900 | 8000 | 9900 | 7300 | 8100 | 8000 | Honda | 3 |
+----+----------+---------+----------+-------+---------+----------+---------+----------+
这是一个选项,您不必枚举要逆透视的列。
这还假设列名的前缀为 a_
示例或dbFiddle
with cte as (
Select *
From YourTable A
Cross Apply (
Select *
,rn=row_number() over (order by convert(decimal(12,2),value) desc)
From OpenJson((Select A.* For JSON Path,Without_Array_Wrapper ))
Where [Key] not in ('ID','SoldCar','CarOrder')
) B
Where [key] ='a_'+SoldCar collate SQL_Latin1_General_CP1_CI_AS
)
Update cte set CarOrder = RN
更新后Table
这个很简单。您只需将前 6 列中当前 SoldCar 的排名附加到相应的记录。在 SQL 中执行此操作很复杂。该语言需要 XQuery 或 OpenJson 和 window 函数辅助的交叉应用。该声明冗长且难以阅读。另一种方法是从数据库中导出数据并在 Python 或 SPL 中处理它。 SPL,open-source Java 包,更容易集成到 Java 程序中并生成更简单的代码。它只用三行代码就完成了:
A
1
=MSSQL.query("select a_Toyota,a_Mazda,a_Nissan,a_Kia,a_Honda,a_Subaru,'a_'+SoldCar as SoldCar from cars")
2
=A1.fname().m(:-2)
3
=A1.derive([${A2.concat@c()}].ranks@z()(A2.pselect(~==A1.~.#7)):CarOrder)
我的 SQL 服务器 table 看起来像这样
ID a_Toyota a_Mazda a_Nissan a_Kia a_Honda a_Subaru SoldCar CarOrder
1 8000 7000 6200 8500 6500 7000 Mazda NULL
2 4000 5000 4500 3500 3500 5000 Mazda NULL
3 5400 5000 4500 5500 5500 4600 Mazda NULL
4 5600 6300 7500 8200 6500 7300 Mazda NULL
5 8500 7400 7400 6500 9500 9000 Mazda NULL
6 9900 8000 9900 7300 8100 8000 Mazda NULL
我想更新 CarOrder 字段,所以它具有已售出汽车的价格与其他汽车价格相比的顺序。
因此,对于 ID 1 的汽车价格,如 a_Kia (8500) 是 1st 和 a_Toyota (8000) 是 2nd 和 a_Mazda & a_Subaru (7000) 是3rd and a_Honda (6500) is 5th and a_Nissan (6200) 是 第 6 售出的汽车是马自达,排名第三,所以 table 应该如下
ID a_Toyota a_Mazda a_Nissan a_Kia a_Honda a_Subaru SoldCar CarOrder
1 8000 7000 6200 8500 6500 7000 Mazda 3
2 4000 5000 4500 3500 3500 5000 Subaru 1
3 5400 5000 4500 5500 5500 4600 Toyota 3
4 5600 6300 7500 8200 6500 7300 Honda 4
5 8500 7400 7400 6500 9500 9000 Honda 1
6 9900 8000 9900 7300 8100 8000 Honda 3
我可以找到带有大 CASE 语句的订单
UPDATE mytable
SET CarOrder =
CASE WHEN SoldCar = 'Toyota' AND a_Toyota>=a_Mazda AND a_Toyota>=a_Nissan AND ... AND a_Toyota>=a_Subaru THEN 1
CASE WHEN SoldCar = 'Toyota' AND a_Toyota<a_Mazda AND a_Toyota>=a_Nissan AND ... AND a_Toyota>=a_Subaru THEN 2
CASE WHEN SoldCar = 'Toyota' AND a_Toyota>=a_Mazda AND a_Toyota<a_Nissan AND ... AND a_Toyota>=a_Subaru THEN 2
.
.
.
CASE WHEN SoldCar = 'Toyota' AND a_Toyota>=a_Mazda AND a_Toyota>=a_Nissan AND ... AND a_Toyota<a_Subaru THEN 2
.
.
.
CASE WHEN SoldCar = 'Toyota' AND a_Toyota<a_Mazda AND a_Toyota<a_Nissan AND ... AND a_Toyota>=a_Subaru THEN 3
..
..
..
但这将是一个巨大的案例陈述。
不知道有人有更简单的方法吗?
假设 table 结构类似于以下内容:
CREATE TABLE tempdb..cars
(
ID INT NOT NULL,
a_Toyota INT NOT NULL,
a_Mazda INT NOT NULL,
a_Nissan INT NOT NULL,
a_Kia INT NOT NULL,
a_Honda INT NOT NULL,
a_Subaru INT NOT NULL,
SoldCar VARCHAR(100) NOT NULL,
CarOrder INT NULL
);
一种方法是利用 APPLY operator. Something like the following should give you a resultset from a table structure like above, assuming the use of CROSS APPLY and a non-dense RANK (vs a DENSE RANK) 以及降序来确定您的顺序:
SELECT c.ID, c.SoldCar, o.ord AS CarOrder
FROM tempdb..cars c
CROSS APPLY
(
SELECT t.ord
FROM (
SELECT r.car, RANK() OVER (ORDER BY r.qty DESC) AS ord
FROM (
SELECT c.a_Toyota AS qty, 'Toyota' AS car
UNION ALL
SELECT c.a_Mazda AS qty, 'Mazda' AS car
UNION ALL
SELECT c.a_Nissan AS qty, 'Nissan' AS car
UNION ALL
SELECT c.a_Kia AS qty, 'Kia' AS car
UNION ALL
SELECT c.a_Honda AS qty, 'Honda' AS car
UNION ALL
SELECT c.a_Subaru AS qty, 'Subaru' AS car
) r
) t
WHERE t.car = c.SoldCar
) o
table 结构需要从一开始就转向它应该有的东西,这将有助于轻松确定正确的顺序并满足任何数量的品牌。
您可以使用交叉应用和 row_number 将每个值与其序号位置相匹配,使用 updatable CTE 更新基础 table。
with cars as (
select * from t
cross apply (
select case soldcar
when 'Toyota' then a_Toyota
when 'Mazda' then a_Mazda
when 'Nissan' then a_Nissan
when 'Honda' then a_Honda
when 'Subaru' then a_Subaru
end
)s(SoldValue)
cross apply (
select rank() over (order by v desc) co, v
from (values(a_toyota),(a_mazda),(a_nissan),(a_kia),(a_honda),(a_subaru))v(v)
)c
where SoldValue=v
)
update cars set carOrder=co
又一个基于XQuery的方法。
对于ID=2的行,Subary和Mazda打成平手。他们都有5000的价值。
SQL
-- DDL and sample data population, start
DECLARE @tbl TABLE (
ID INT IDENTITY(1,1) PRIMARY KEY,
a_Toyota INT,
a_Mazda INT,
a_Nissan INT,
a_Kia INT,
a_Honda INT,
a_Subaru INT,
SoldCar VARCHAR(20)
);
INSERT INTO @tbl
(
a_Toyota,
a_Mazda,
a_Nissan,
a_Kia,
a_Honda,
a_Subaru,
SoldCar
) VALUES
(8000, 7000, 6200, 8500, 6500, 7000, 'Mazda'),
(4000, 5000, 4500, 3500, 3500, 5000, 'Subaru'),
(5400, 5000, 4500, 5500, 5500, 4600, 'Toyota'),
(5600, 6300, 7500, 8200, 6500, 7300, 'Honda'),
(8500, 7400, 7400, 6500, 9500, 9000, 'Honda'),
(9900, 8000, 9900, 7300, 8100, 8000, 'Honda');
-- DDL and sample data population, end
SELECT t.*, CarOrder
FROM @tbl AS t
CROSS APPLY (SELECT a_Toyota, a_Mazda, a_Nissan,
a_Kia, a_Honda, a_Subaru, SoldCar
FOR XML PATH(''), TYPE, ROOT('root')) AS t1(c)
CROSS APPLY (SELECT c.query('<root>
{
for $r in /root/*
order by data($r) descending
return <r>
<make>{local-name($r)}</make>
<salePrice>{data($r)}</salePrice>
</r>
}
</root>').query('
let $soldcar := sql:column("SoldCar")
for $r in /root/r[contains((make/text())[1], $soldcar)]
let $pos := count(root/*[. << $r])
return $pos').value('.','INT')
) AS t2(CarOrder);
输出
+----+----------+---------+----------+-------+---------+----------+---------+----------+
| ID | a_Toyota | a_Mazda | a_Nissan | a_Kia | a_Honda | a_Subaru | SoldCar | CarOrder |
+----+----------+---------+----------+-------+---------+----------+---------+----------+
| 1 | 8000 | 7000 | 6200 | 8500 | 6500 | 7000 | Mazda | 3 |
| 2 | 4000 | 5000 | 4500 | 3500 | 3500 | 5000 | Subaru | 2 |
| 3 | 5400 | 5000 | 4500 | 5500 | 5500 | 4600 | Toyota | 3 |
| 4 | 5600 | 6300 | 7500 | 8200 | 6500 | 7300 | Honda | 4 |
| 5 | 8500 | 7400 | 7400 | 6500 | 9500 | 9000 | Honda | 1 |
| 6 | 9900 | 8000 | 9900 | 7300 | 8100 | 8000 | Honda | 3 |
+----+----------+---------+----------+-------+---------+----------+---------+----------+
这是一个选项,您不必枚举要逆透视的列。
这还假设列名的前缀为 a_
示例或dbFiddle
with cte as (
Select *
From YourTable A
Cross Apply (
Select *
,rn=row_number() over (order by convert(decimal(12,2),value) desc)
From OpenJson((Select A.* For JSON Path,Without_Array_Wrapper ))
Where [Key] not in ('ID','SoldCar','CarOrder')
) B
Where [key] ='a_'+SoldCar collate SQL_Latin1_General_CP1_CI_AS
)
Update cte set CarOrder = RN
更新后Table
这个很简单。您只需将前 6 列中当前 SoldCar 的排名附加到相应的记录。在 SQL 中执行此操作很复杂。该语言需要 XQuery 或 OpenJson 和 window 函数辅助的交叉应用。该声明冗长且难以阅读。另一种方法是从数据库中导出数据并在 Python 或 SPL 中处理它。 SPL,open-source Java 包,更容易集成到 Java 程序中并生成更简单的代码。它只用三行代码就完成了:
A | |
---|---|
1 | =MSSQL.query("select a_Toyota,a_Mazda,a_Nissan,a_Kia,a_Honda,a_Subaru,'a_'+SoldCar as SoldCar from cars") |
2 | =A1.fname().m(:-2) |
3 | =A1.derive([${A2.concat@c()}].ranks@z()(A2.pselect(~==A1.~.#7)):CarOrder) |