有沒有辦法將一列中的多個值與另一列中的單個值進行比較。
例子:
- A列包含:
[a;b;c;d] - B列包含:
[a]
目前我正在使用LIKE運算子來實作這一點,但不是結果。我用通配符嘗試過,%但由于;.
uj5u.com熱心網友回復:
正如 Larnu 所建議的,這里真正的解決方法是修復設計。你應該回到所有者那里,提醒他們資料庫是用來存盤關系資料的;如果您將多個“事實”塞進一列,您不妨使用平面檔案。例外情況是,如果您為應用程式存盤一個逗號分隔的串列,并且只有應用程式負責組裝和分解該集合。
無論如何,鑒于您可能對此很困惑(假設ColumnA限制為 128 個字符):
CREATE TABLE dbo.BadDesign
(
ColumnA nvarchar(128),
ColumnB nvarchar(max)
);
INSERT dbo.BadDesign(ColumnA, ColumnB) VALUES
(N'[a]', N'[a;b;c;d]'), -- only match
(N'[p]', N'[q;r;s]'),
(N'[h]', N'[hi;j;k]');
您可以在此 db<>fiddle中依次看到以下解決方案:
嵌套替換
在過去(SQL Server 2017)之前,我們會執行嵌套REPLACE()呼叫以去除方括號并用分隔符替換字串的每一端:
-- All versions
SELECT ColumnA, ColumnB
FROM dbo.BadDesign
WHERE REPLACE(REPLACE(ColumnB, N'[',N';'),N']', N';')
LIKE N'%' REPLACE(REPLACE(ColumnA ,N'[',N';'),N']', N';') N'%';
毛,但結果:
| A列 | B列 |
|---|---|
| [一種] | [A B C D] |
我們不能TRIM()在 SQL Server 2017 之前的版本上使用,但我在下面解釋了為什么我們不想在現代版本上使用該功能。
打開Json
在 2016 中,我們可以OPENJSON在對字串進行一些操作后使用。在這里,我使用了一個PARSENAME()技巧,只有ColumnA<= 128 個字符時才安全。我在這個 db<>fiddle 中展示了其他解決方法:
SELECT b.ColumnA, b.ColumnB
FROM dbo.BadDesign AS b
CROSS APPLY OPENJSON(REPLACE(REPLACE(REPLACE(
b.ColumnB, N'[', N'["'), N']', N'"]"'), N';', N'","')) AS j
WHERE j.value = PARSENAME(b.ColumnA, 1);
結果:
| A列 | B列 |
|---|---|
| [一種] | [A B C D] |
翻譯
在 SQL Server 2017 中,它可以不那么粗糙TRANSLATE():
-- SQL Server 2017
SELECT ColumnA, ColumnB
FROM dbo.BadDesign
WHERE TRANSLATE(ColumnB, N'[]',N';;')
LIKE N'%' TRANSLATE(ColumnA, N'[]',N';;') N'%';
| A列 | B列 |
|---|---|
| [一種] | [A B C D] |
We don't want to use TRIM() here because we don't simply want to remove the enclosing square brackets; we want delimiters there so we can always compare A to B regardless of where B is in the string. Without surrounding delimiters replaced or translated, we could get inaccurate results if the match is at the beginning or end of the multi-value string.
Split Function
Alternatively, you could create this function on SQL Server 2016 (or a messier one that doesn't use STRING_SPLIT() in earlier versions - as Smor noted, a search will turn up hundreds of those):
CREATE FUNCTION dbo.SplitAndClean(@s nvarchar(max))
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN
(
SELECT value
FROM STRING_SPLIT
(
-- if 2016:
REPLACE(REPLACE(@s, N'[',N';'),N']', N';'),
-- if 2017 , TRANSLATE() is slightly cleaner:
/* TRANSLATE(@s, N'[]',N';;'), */
N';'
)
WHERE value > N''
);
Then you can say:
SELECT bd.ColumnA, bd.ColumnB
FROM dbo.BadDesign AS bd
CROSS APPLY dbo.SplitAndClean(bd.ColumnA) AS a
CROSS APPLY dbo.SplitAndClean(bd.ColumnB) AS b
WHERE a.value = b.value;
| ColumnA | ColumnB |
|---|---|
| [a] | [a;b;c;d] |
But in the end...
...these are all gross "solutions" masking bad design, and you should really have them reconsider how they're using the database.
我知道許多商店不能只切換到使用TVP在應用程式和資料庫之間傳遞集合,因為一些客戶端提供商和 ORM 還沒有完全趕上這趟火車。如果你不能使用TVPs或者不能改變應用程式,你至少應該考慮攔截應用程式傳遞的逗號分隔串列并使用SPLIT_STRING()之類的方法將其分開。然后,您可以以關系方式存盤這些值,讓資料庫執行資料庫設計的任務,而不受應用程式限制的束縛。
uj5u.com熱心網友回復:
如果在您的示例中 col_b 中始終只有一個值,您可以使用嵌套替換函式洗掉 [ 和 ] 然后使用“like”進行搜索
select *
from test_data
where col_a like '%' replace(replace(col_b, '[', ''), ']', '') '%';
但
如果 col_b 中可能有多個值并且它可以按任何順序排列(例如“[a;c]”或“[d;a]”),您將在已回答的問題中找到答案,或者您可以在谷歌上搜索“string_split” ()” msdn 上的函式。后者有很好的例子部分,肯定會幫助你
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/311537.html
標籤:sql-server 查询语句 类似sql
