【问题标题】:Setting multiple variables' value in one IIF() of a SELECT statement在 SELECT 语句的一个 IIF() 中设置多个变量的值
【发布时间】:2020-04-13 10:07:11
【问题描述】:

我有一个 CROSS JOIN 查询,我正在使用它来查看哪个项目数量组合产生最佳输出。

DECLARE @last_found DECIMAL(10, 2) = 0
DECLARE @calculated DECIMAL(10, 2)
DECLARE @n_count INT
DECLARE @tbl1n INT
DECLARE @tbl2n INT
DECLARE @tbl3n INT


DROP TABLE IF EXISTS #tbl1
DROP TABLE IF EXISTS #tbl2
DROP TABLE IF EXISTS #tbl3

;WITH numbers AS (
    SELECT ROW_NUMBER() OVER (ORDER BY [value]) AS n
    FROM string_split('1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20', ',')
)
SELECT n, (n * 10000 * (1 + IIF(n > 1, (0.50/19.00) * (n - 1), 0))) AS price
INTO #tbl1 FROM numbers

;WITH numbers AS (
    SELECT ROW_NUMBER() OVER (ORDER BY [value]) AS n
    FROM string_split('1,2,3,4,5,6,7,8,9,10,11,12', ',')
)
SELECT n, (n * 15000 * (1 + IIF(n > 1, (0.50/11.00) * (n - 1), 0))) AS price
INTO #tbl2 FROM numbers

;WITH numbers AS (
    SELECT ROW_NUMBER() OVER (ORDER BY [value]) AS n
    FROM string_split('1,2,3,4,5,6', ',')
)
SELECT n, (n * 20000 * (1 + IIF(n > 1, (0.50/5.00) * (n - 1), 0))) AS price
INTO #tbl3 FROM numbers


SELECT
    @n_count = (tbl1.n + tbl2.n + tbl3.n),
    @calculated = IIF(@n_count = 10, (tbl1.price + tbl2.price + tbl3.price), 0),
    @tbl1n = IIF(@calculated > @last_found, tbl1.n, @tbl1n),
    @tbl2n = IIF(@calculated > @last_found, tbl2.n, @tbl2n),
    @tbl3n = IIF(@calculated > @last_found, tbl3.n, @tbl3n),
    @last_found = IIF(@calculated > @last_found, @calculated, @last_found)
FROM #tbl1 tbl1
CROSS JOIN #tbl2 tbl2
CROSS JOIN #tbl3 tbl3


SELECT @last_found AS highest_value, @tbl1n AS tbl1n, @tbl2n AS tbl2n, @tbl3n AS tbl3n,
    t1.price AS tbl1_price, t2.price AS tbl2_price, t3.price AS tbl3_price
FROM #tbl1 t1
INNER JOIN #tbl2 t2 ON t1.n = @tbl1n AND t2.n = @tbl2n
INNER JOIN #tbl3 t3 ON t3.n = @tbl3n

可以看出,如果查询找到的值高于先前找到的最高值,它会使用多个 @itemN = IIF(@calculated > @last_found, tbl.n, @itemN) 实例存储组合。

是否可以一次性分配所有@tblXn 变量?我可以使用 CONCAT,但我认为它可能会减慢查询速度,因为它是一个字符串操作。

仅供参考 - 'n' 是一个介于 0 和 20 之间的值。

【问题讨论】:

  • 给出示例数据以及该数据中所需的最终结果。将有一种更简单的方法来做你想做的事情,但 TBH 目前还不清楚,因为你依赖于多行变量赋值的无证行为,并且因为你使用表达式分配给 @last_found 之类的问题@calculated > @last_found 然后你再次使用相同的表达式之后它刚刚被分配给
  • 还不清楚@calculated = IIF(@n_count = 10, ((tbl1.n * tbl1.price), (tbl2.n * tbl2.price), (tbl3.n * tbl3.price)), 0) 的含义,因为这不是有效的语法
  • @MartinSmith 添加样本数据并输出到查询

标签: sql sql-server variables iif cross-join


【解决方案1】:

你可以使用apply

SELECT n_count, calculated, last_found,
       IIF(flag = 1, tbl1.n, @tbl1n) AS tbl1n,
       IIF(flag = 1, tbl2.n, @tbl2n) AS tbl2n,
       IIF(flag = 1, tbl3.n, @tbl3n) AS tbl3n
FROM tbl1 CROSS JOIN 
     tbl2 CROSS JOIN 
     tb CROSS APPLY
     ( VALUES (tbl1.n + tbl2.n + tbl3.n) 
     ) t(n_count) CROSS APPLY
     ( VALUES (IIF(n_count = 10, ( (tbl1.n * tbl1.price), (tbl2.n * tbl2.price), (tbl3.n * tbl3.price) ), 0))
     ) tt(calculated) CROSS APPLY
     ( VALUES (IIF(calculated > @last_found, calculated, @last_found)) 
     ) lst(last_found) CROSS APPLY
     ( VALUES (IIF(calculated > last_found, 1, 0)) 
     ) cc(flag)

注意:您可以进一步为变量赋值。

【讨论】:

  • 这个查询仍然检查IIF(calculated > last_found, 四次,但是为了更容易检索找到的值而编写。将保持问题开放,看看是否有人有其他选择。
  • @ShahidThaika。 . .您可以再添加一个apply
  • 这忽略了 @last_found 在整个过程中都不是静态的,而是被分配给然后影响未来与变量比较的事实
【解决方案2】:

您根本不应该为此使用变量。

这样写起来会更简单(不依赖于跨多行变量赋值的无证/无保证行为)

SELECT TOP 1 CAST(combined_price AS DECIMAL(10, 2)) AS highest_value,
             tbl1.n                                 AS tbl1n,
             tbl2.n                                 AS tbl2n,
             tbl3.n                                 AS tbl3n,
             tbl1.price                             AS tbl1_price,
             tbl2.price                             AS tbl2_price,
             tbl3.price                             AS tbl3_price
FROM   #tbl1 tbl1
       CROSS JOIN #tbl2 tbl2
       CROSS JOIN #tbl3 tbl3
       CROSS APPLY (VALUES (tbl1.price + tbl2.price + tbl3.price, 
                            tbl1.n + tbl2.n + tbl3.n)) CA(combined_price, combined_n)
WHERE  combined_n = 10
ORDER  BY combined_price DESC 

【讨论】:

  • 我确实考虑过 ORDER BY,但我的实际查询有 11 个表,计算比 price1 + price2 + price3 复杂得多。如果我使用 ORDER BY,SQL Server 会先将输出写入磁盘然后再排序,还是保持纯内存/cpu 操作?
  • TOP N Sort with N = 1 只需要跟踪迄今为止看到的最高值的行,它不需要对整个结果集进行排序。如果 N 是 gte 100,你只会得到一个完整的排序。sql.kiwi/2010/08/sorting-row-goals-and-the-top-100-problem.html
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-12
  • 2014-07-26
  • 1970-01-01
  • 2021-11-09
  • 2020-06-19
相关资源
最近更新 更多