提问人:Greg 提问时间:6/29/2023 最后编辑:Greg 更新时间:6/29/2023 访问量:100
视图中的“模拟”变量
"Simulate" Variables in a View
问:
背景
再一次,我在一个非常受限的 T-SQL 环境中工作,在这个环境中,人们只能定义 : 大概是VIEW
...
CREATE VIEW My_View AS ...
在引擎盖下。必须(作为 SQL)编写在应用程序 GUI 中其自己的文本字段中,这会带来某些不灵活性,如注释中所述。...
这是我@@VERSION
:
Microsoft SQL Server 2019 (RTM-CU19) (KB5023049) - 15.0.4298.1 (X64)
Jan 27 2023 16:44:09
Copyright (C) 2019 Microsoft Corporation
Web Edition (64-bit) on Linux (Amazon Linux 2) <X64>
注意
正文 (...
) 仅限于单个 SQL 语句!此外,存储的 s 也无法发挥作用。PROCEDURE
目标
我希望“模拟”“局部”变量的存在,以便可以动态更新某些条件,而不是在整个查询过程中硬编码为文字。具体来说,我希望这些“变量”位于顶部,以便可以轻松调整它们。
问题
遗憾的是,表单的变量在视图中不可用。@x
方法
我假设了这种方法,其“字段”是变量的 CTE。它们的值可以作为以下形式的子查询进行访问:vars
(SELECT x FROM vars)
/*********************
** Variable Scalars **
**********************/
WITH vars AS (SELECT
'Greg' AS c_name, -- A client named "Greg".
GETDATE() AS t_date -- Transactions occurring today.
/**********
** Query **
**********/
) SELECT
*
FROM
Transactions
WHERE
-- |-------- 'Greg' -------|
Client_Name = (SELECT c_name FROM vars) AND
Transaction_Date = (SELECT t_date FROM vars)
-- |--------- Today -------|
我进一步建议,可以将值的变量列表指定为进一步的 CTE,通过 STRING_SPLIT()
派生:
/*********************
** Variable Scalars **
**********************/
WITH vars AS (SELECT
'Greg' AS c_name
/******************
** Variable List **
*******************/
), vars_dates AS (SELECT DISTINCT CAST([Value] AS DATE) AS vals FROM STRING_SPLIT('
2023-06-28
2023-06-01
2023-01-01
', Char(10)) WHERE [Value] <> ''
/**********
** Query **
**********/
) SELECT
*
FROM
Transactions
WHERE
-- |----------- 'Greg' ----------|
Client_Name = (SELECT c_name FROM vars ) AND
Transaction_Date IN (SELECT vals FROM vars_dates)
-- |-----------------------------|
-- {1/1/23, 6/1/23, 6/28/23}
请注意,现在每个值都列在单独的行上,因此用户不必担心标点符号(逗号等)与任何分隔符冲突。vars_dates
问题
到目前为止,我已经能够调用任何需要值的地方。事实上,在我的整个用例中,两者都完美地工作。(SELECT x FROM vars)
x
vars
vars_dates
但是,是否有任何情况,这些表达式不起作用,而不是文字值和列表?更一般地说,这种方法的局限性是什么?
答:
您只想在顶部定义一次一些值,然后在整个视图中的重复点中使用它们,以便将来可以在某个位置更改它们。
鉴于您正在使用的约束,您拥有的方法似乎没问题(如果不需要在其他视图中共享这些值)。
它基本上是“伪常量”思想的更局部范围的版本,至少对于标量值,SQL Server 应该能够使用基础文本值进行基数估计(在这方面比实际的 TSQL @variable更好)。
对于标量值,而不是像我这样的子查询,我会介意只使用单行,这样列就可以更容易使用。请在此处查看此示例:SELECT c_name FROM vars
CROSS JOIN
vars
-- An example table, in place of 'Transactions'.
CREATE TABLE #T(X INT);
INSERT INTO #T VALUES (1),(2),(2),(3),(3),(3);
-- The CROSS technique itself.
WITH vars AS
(
SELECT 3 AS foo
)
SELECT #T.*
FROM vars
CROSS JOIN #T
WHERE X = vars.foo
-- Cleanup.
DROP TABLE #T
下面演示了使用该值完成的基数估计,并且它正确地估计了 3 行。3
对于列表,我可能会使用表值构造函数而不是字符串拆分。它应该允许 SQL Server 更轻松地查看列表中的行数(如果它查看这些行中的实际值,可能会对基数估计有其他好处)。
-- ...
/******************
** Variable List **
******************/
), vars_dates AS (SELECT vals FROM (VALUES
(CAST('2023-06-28' AS date)), /*So the column from the constant scan is typed as date*/
('2023-06-01'),
('2023-01-01')
) tbl(vals)
-- ...
与实际变量不同,如果您使用非确定性函数,则此方法无法保证值在整个查询过程中保持不变,但您没有任何方法在当前约束下实际保证这一点。
评论
tbl
col
date
varchar
GETDATE()
一样。STRING_SPLIT()
VALUES ((
), ('2023-06-01'), ...) tbl(vals)
评论
VALUES
SELECT FROM