在 T-SQL 中是不是有一个内置命令来确定一个数字是不是在另一个表的范围内
Posted
技术标签:
【中文标题】在 T-SQL 中是不是有一个内置命令来确定一个数字是不是在另一个表的范围内【英文标题】:In T-SQL is there a built-in command to determine if a number is in a range from another table在 T-SQL 中是否有一个内置命令来确定一个数字是否在另一个表的范围内 【发布时间】:2017-05-17 21:20:38 【问题描述】:这不是家庭作业。
我正在尝试计算订单中的 T 恤数量,并查看衬衫属于哪个价格范围,具体取决于已订购的数量。 我最初的想法(我是全新的)是询问另一张桌子是否计数 > 第一价格范围的最大值,如果是这样,请继续寻找直到它不是。
printing_range_max printing_price_by_range
15 4
24 3
33 2
例如,如果订单数量为 30 件衬衫,则每件为 2 美元。
当我研究如何做到这一点时,看起来大多数人都在使用 BETWEEN 或 IF 并对范围进行硬编码,而不是查看另一个表。我想在商业环境中,最好能够将范围留在自己的表格中,以便更轻松地更改它。有没有一种好的/内置方法可以做到这一点,还是我应该用 BETWEEN 命令或 IF 语句将其写入?
编辑: SQL Server 2014
【问题讨论】:
我想在商业环境中最好在每个价格范围内同时设置最小值和最大值...... @JoshPart 我相信以编程方式设置最小和最大范围会更简单。但是,TSQL 在 LEAD 和 LAG 中具有功能,可以让您提供其中之一并仍然实现您的目标,但查询将不太理想。我建议您阅读一下这两个窗口函数,看看它们是否能解决您的需求。 提示:使用适当的软件(mysql、Oracle、DB2 等)和版本标记数据库问题很有帮助,例如sql-server-2014
。语法和功能的差异通常会影响答案。
【参考方案1】:
假设我们有这张桌子:
DECLARE @priceRanges TABLE(printing_range_max tinyint, printing_price_by_range tinyint);
INSERT @priceRanges VALUES (15, 4), (24, 3), (33, 2);
您可以创建一个表格,其中包含代表正确价格的范围。以下是在 2012 年之前和 2012 年之后的系统中如何做到这一点:
DECLARE @priceRanges TABLE(printing_range_max tinyint, printing_price_by_range tinyint);
INSERT @priceRanges VALUES (15, 4), (24, 3), (33, 2);
-- post-2012 using LAG
WITH pricerange AS
(
SELECT
printing_range_min = LAG(printing_range_max, 1, 0) OVER (ORDER BY printing_range_max),
printing_range_max,
printing_price_by_range
FROM @priceRanges
)
SELECT * FROM pricerange;
-- pre-2012 using ROW_NUMBER and a self-join
WITH prices AS
(
SELECT
rn = ROW_NUMBER() OVER (ORDER BY printing_range_max),
printing_range_max,
printing_price_by_range
FROM @priceRanges
),
pricerange As
(
SELECT
printing_range_min = ISNULL(p2.printing_range_max, 0),
printing_range_max = p1.printing_range_max,
p1.printing_price_by_range
FROM prices p1
LEFT JOIN prices p2 ON p1.rn = p2.rn+1
)
SELECT * FROM pricerange;
两个查询都返回:
printing_range_min printing_range_max printing_price_by_range
------------------ ------------------ -----------------------
0 15 4
15 24 3
24 33 2
现在您可以使用 BETWEEN 进行加入。这是完整的解决方案:
-- Sample data
DECLARE @priceRanges TABLE
(
printing_range_max tinyint,
printing_price_by_range tinyint
-- if you're on 2014+
,INDEX ix_xxx NONCLUSTERED(printing_range_max, printing_price_by_range)
-- note: second column should be an INCLUDE but not supported in table variables
);
DECLARE @orders TABLE
(
orderid int identity,
ordercount int
-- if you're on 2014+
,INDEX ix_xxy NONCLUSTERED(orderid, ordercount)
-- note: second column should be an INCLUDE but not supported in table variables
);
INSERT @priceRanges VALUES (15, 4), (24, 3), (33, 2);
INSERT @orders(ordercount) VALUES (10), (20), (25), (30);
-- Solution:
WITH pricerange AS
(
SELECT
printing_range_min = LAG(printing_range_max, 1, 0) OVER (ORDER BY printing_range_max),
printing_range_max,
printing_price_by_range
FROM @priceRanges
)
SELECT
o.orderid,
o.ordercount,
--p.printing_range_min,
--p.printing_range_max
p.printing_price_by_range
FROM pricerange p
JOIN @orders o ON o.ordercount BETWEEN printing_range_min AND printing_range_max
结果:
orderid ordercount printing_price_by_range
----------- ----------- -----------------------
1 10 4
2 20 3
3 25 2
4 30 2
现在我们可以了
【讨论】:
给定表格:“INSERT @priceRanges VALUES (15,4), (24,3), (33,2);"这给了我每个范围的最大值,以及该范围的价格。然后你做了一个滞后来临时找到/创建最小值。然后根据表驱动的 maxPrice 和 temp minPrice 上的 BETWEEN 函数的结果加入表。 好吧,我注意到了一件事,但我不知道如何减少最小值或增加最大值,以免范围重叠。按原样,我得到 0-15、15-24 等。现在我正在寻找将值传递给变量并使用该变量代替其位置以获得最终输出的方法。是否有更好的方法或者可以在 CTE 本身中完成对 LAG 或 LEAD 的更改? WELLLLLL 我想多了。显然,只需在该行上加上 +1 即可。 print_range_min = LAG(printing_range_max, 1, 0) OVER (ORDER BY printing_range_max) +1,以上是关于在 T-SQL 中是不是有一个内置命令来确定一个数字是不是在另一个表的范围内的主要内容,如果未能解决你的问题,请参考以下文章
如何使用相同的SqlConnection对象在多个SqlCommands中声明和使用T-SQL变量来执行多个插入?
我可以执行 T-SQL 查询来确定 SQL Server Express 实例的最大数据大小吗?