SQL Server 版本为 2016+/Azure SqlDb(如果添加则灵活,两者兼容,向前兼容)。
用例是 API 用户发送单列值列表来过滤某些目标表。目标表有 2-n 列,其值在被查询的表/范围的行(可能是列,无关紧要)中是唯一的。 (到目前为止n <= 5,但这是一个细节/不能保证。)
这是一个足够好的示例表 DDL:
IF NOT EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'SomeTable')
BEGIN
CREATE TABLE dbo.SomeTable (
ID int IDENTITY(1, 1) not null PRIMARY KEY CLUSTERED
, NaturalKey1 nvarchar(10) not null UNIQUE NONCLUSTERED
, NaturalKey2 nvarchar(10) not null UNIQUE NONCLUSTERED
, NaturalKey3 nvarchar(10) not null UNIQUE NONCLUSTERED
);
END
IF NOT EXISTS (SELECT 1 FROM dbo.SomeTable)
BEGIN
INSERT INTO dbo.SomeTable VALUES
('A', 'AA', 'ZZZZZ')
,('B', 'B', 'YYYYY')
,('C', 'CC', 'XXX')
,('D', 'DDD', 'WWWWW')
,('E', 'EEEE', 'V')
,('F', 'FF', 'UUUUUUUUU')
,('G', 'GGGGGGGG', 's')
-- lots more
;
END
SELECT * FROM dbo.SomeTable;
-- DROP TABLE dbo.SomeTable;
假设所有 NaturalKey
列都是相同类型(可能是 nvarchar
);过滤发生在数据库端;并在存储过程中以尽可能少的步骤执行,最好是一次执行。参数将是字符串列表或 TVP,实际上并不重要。结果将包括 SomeTable
的任何行中与任何列上的任何值匹配的所有数据。目标表的大小未知。
这是我们上面朋友的示例参数:
DECLARE @filterValues nvarchar(1000) = 'DDD,XXX,E,HH,ok,whatever,YYYYY';
SELECT * FROM string_split(@filterValues, ',');
我知道几种方法可以做到这一点,并且可以想象更多的方法,所以它不会被卡住。我敢打赌,有人知道比我将要说明的两个技巧中的任何一个都更好的技巧。
方法 1 构建一个临时表更新并加入它(简洁且易于审计,这对专业人士来说是这样)
DECLARE @filterValues nvarchar(1000) = 'DDD,XXX,E,HH,ok,whatever,YYYYY';
SELECT value AS InValue, CONVERT(int, null) AS IDMatch
INTO #filters
FROM string_split(@filterValues, ',');
UPDATE f
SET f.IDMatch = st.ID
FROM #filters AS f
INNER JOIN dbo.SomeTable AS st ON f.InValue IN (st.NaturalKey1, st.NaturalKey2, st.NaturalKey3);
SELECT * FROM #filters; -- Audit
SELECT st.* FROM #filters AS f INNER JOIN dbo.SomeTable AS st ON f.IDMatch = st.ID;
IF OBJECT_ID('tempdb..#filters') IS NOT NULL DROP TABLE #filters;
方法 2 取消旋转 SomeTable
(我喜欢漂亮的 cross apply trick)并加入(大规模地有我认为的食人魔)
SELECT
st.*
FROM
dbo.SomeTable AS st
CROSS APPLY (VALUES (st.NaturalKey1)
, (st.NaturalKey2)
, (st.NaturalKey3)
) AS nk(Val)
INNER JOIN #filters AS f ON nk.Val = f.InValue;
IF OBJECT_ID('tempdb..#filters') IS NOT NULL DROP TABLE #filters;
我们的未来有问题吗
有效总比无效要好,但要从 T-SQL 专家那里寻找更好/更有效/更具可扩展性的方法。列和行中的未知维度,响应时间是 SLA,过滤器大小可能有上限,也可能没有上限。如果这整齐地从 SomeTable
移植到 SomeTableVersionN
,则加分。 (API 中没有动态 SQL。)
可能是骗人的问题,找不到,指出就好了,谢谢。