JBo*_*ond 5 sql t-sql sql-server stored-procedures
我有一个名为ClientUrls具有以下结构的表:
+------------+----------------+----------+
| ColumnName | DataType | Nullable |
+------------+----------------+----------+
| ClientId | INT | No |
| CountryId | INT | Yes |
| RegionId | INT | Yes |
| LanguageId | INT | Yes |
| URL | NVARCHAR(2048) | NO |
+------------+----------------+----------+
Run Code Online (Sandbox Code Playgroud)
我有一个存储过程up_GetClientUrls,它采用以下参数:
@ClientId INT
@CountryId INT
@RegionId INT
@LanguageId INT
Run Code Online (Sandbox Code Playgroud)
关于过程的信息
优先级矩阵(1为第一)
+---------+----------+-----------+----------+------------+
| Ranking | ClientId | CountryId | RegionId | LanguageId |
+---------+----------+-----------+----------+------------+
| 1 | NOT NULL | NOT NULL | NOT NULL | NOT NULL |
| 2 | NOT NULL | NULL | NOT NULL | NOT NULL |
| 3 | NOT NULL | NOT NULL | NULL | NOT NULL |
| 4 | NOT NULL | NULL | NULL | NOT NULL |
| 5 | NOT NULL | NOT NULL | NOT NULL | NULL |
| 6 | NOT NULL | NULL | NOT NULL | NULL |
| 7 | NOT NULL | NULL | NULL | NULL |
+---------+----------+-----------+----------+------------+
Run Code Online (Sandbox Code Playgroud)
以下是一些示例数据:
+----------+-----------+----------+------------+-------------------------------+
| ClientId | CountryId | RegionId | LanguageId | URL |
+----------+-----------+----------+------------+-------------------------------+
| 1 | 1 | 1 | 1 | http://www.Website.com |
| 1 | 1 | 1 | NULL | http://www.Otherwebsite.com |
| 1 | 1 | NULL | 2 | http://www.Anotherwebsite.com |
+----------+-----------+----------+------------+-------------------------------+
Run Code Online (Sandbox Code Playgroud)
示例存储过程调用
EXEC up_GetClientUrls @ClientId = 1
,@CountryId = 1
,@RegionId = 1
,@LanguageId = 2
Run Code Online (Sandbox Code Playgroud)
预期响应(基于示例数据)
+----------+-----------+----------+------------+-------------------------------+
| ClientId | CountryId | RegionId | LanguageId | URL |
+----------+-----------+----------+------------+-------------------------------+
| 1 | 1 | NULL | 2 | http://www.Anotherwebsite.com |
+----------+-----------+----------+------------+-------------------------------+
Run Code Online (Sandbox Code Playgroud)
返回此行是因为NULL RegionId与正确的LanguageId匹配的优先级高于使用正确RegionId的NULL LanguageId匹配.
这是proc的代码(有效).要真正回答我的问题,有没有更好的方法来写这个?如果我将来扩展这个表,我将继续增加UNION语句的数量,因此它不是真正可扩展的.
实际存储过程
CREATE PROC up_GetClientUrls
(
@ClientId INT
,@CountryId INT
,@RegionId INT
,@LanguageId INT
)
AS
BEGIN
SELECT TOP 1
prioritised.ClientId
,prioritised.CountryId
,prioritised.RegionId
,prioritised.LanguageId
,prioritised.URL
FROM
(
SELECT
c.ClientId
,c.CountryId
,c.RegionId
,c.LanguageId
,c.URL
,1 [priority]
FROM ClientUrls c
WHERE c.ClientId = @ClientId
AND c.CountryId = @CountryId
AND c.RegionId = @RegionId
AND c.LanguageId = @LanguageId
UNION
SELECT
c.ClientId
,c.CountryId
,c.RegionId
,c.LanguageId
,c.URL
,2 [priority]
FROM ClientUrls c
WHERE c.ClientId = @ClientId
AND c.CountryId IS NULL
AND c.RegionId = @RegionId
AND c.LanguageId = @LanguageId
UNION
SELECT
c.ClientId
,c.CountryId
,c.RegionId
,c.LanguageId
,c.URL
,3 [priority]
FROM ClientUrls c
WHERE c.ClientId = @ClientId
AND c.CountryId = @CountryId
AND c.RegionId IS NULL
AND c.LanguageId = @LanguageId
UNION
SELECT
c.ClientId
,c.CountryId
,c.RegionId
,c.LanguageId
,c.URL
,4 [priority]
FROM ClientUrls c
WHERE c.ClientId = @ClientId
AND c.CountryId IS NULL
AND c.RegionId IS NULL
AND c.LanguageId = @LanguageId
UNION
SELECT
c.ClientId
,c.CountryId
,c.RegionId
,c.LanguageId
,c.URL
,5 [priority]
FROM ClientUrls c
WHERE c.ClientId = @ClientId
AND c.CountryId = @CountryId
AND c.RegionId = @RegionId
AND c.LanguageId IS NULL
UNION
SELECT
c.ClientId
,c.CountryId
,c.RegionId
,c.LanguageId
,c.URL
,6 [priority]
FROM ClientUrls c
WHERE c.ClientId = @ClientId
AND c.CountryId IS NULL
AND c.RegionId = @RegionId
AND c.LanguageId IS NULL
UNION
SELECT
c.ClientId
,c.CountryId
,c.RegionId
,c.LanguageId
,c.URL
,7 [priority]
FROM ClientUrls c
WHERE c.ClientId = @ClientId
AND c.CountryId IS NULL
AND c.RegionId IS NULL
AND c.LanguageId IS NULL
) prioritised
ORDER BY prioritised.[Priority]
END
Run Code Online (Sandbox Code Playgroud)
这很容易(如果我理解正确的话)。您只需很少的代码就可以做到这一点。另外,如果需要的话,它很容易扩展。
这是一个工作示例
--Make a table
CREATE TABLE #ClientUrls (ClientId INT NOT NULL,CountryId INT NULL,RegionId INT NULL,LanguageId INT NULL,URL NVARCHAR(2048) NOT NULL)
--Put some data into it
INSERT INTO #ClientUrls (ClientId, CountryId, RegionId, LanguageId, URL)
VALUES
(1,1,1,1,'http://www.Website.com'),
(1,1,1,NULL,'http://www.Otherwebsite.com'),
(1,1,NULL,2,'http://www.Anotherwebsite.com')
--This would all be in your proc
----------------------------------------------
DECLARE @ClientId INT = 1
DECLARE @CountryId INT = 1
DECLARE @RegionId INT = 1
DECLARE @LanguageId INT = 2
--This is the interesting bit
----------------------------------------------
SELECT TOP 1 C.*
FROM #ClientUrls AS C
ORDER BY
--Order the ones with the best hit count near the top
IIF(ISNULL(C.ClientId, @ClientId) = @ClientId ,1,0) +
IIF(ISNULL(C.CountryId, @CountryId) = @CountryId ,2,0) +
IIF(ISNULL(C.RegionId, @RegionId) = @RegionId ,4,0) +
IIF(ISNULL(C.LanguageId,@LanguageId) = @LanguageId,8,0) DESC,
--Order the ones with the least nulls of each hit count near the top
IIF(C.ClientId IS NULL,0,1) +
IIF(C.CountryId IS NULL,0,2) +
IIF(C.RegionId IS NULL,0,4) +
IIF(C.LanguageId IS NULL,0,8) DESC
DROP TABLE #ClientUrls
Run Code Online (Sandbox Code Playgroud)
就是这样。在旧版本的 SQL 中,您不能使用 IIF,但如果需要,您可以用 case 语句替换它。
它的工作原理是这样的。
每个匹配项都有一个值(有点像二进制数),然后根据每个匹配项,我们使用该值;如果不匹配,则使用 0,通过将总数相加,我们将始终选择最佳匹配组合。
value 1 2 4 8 Total value
+---------+----------+-----------+----------+------------+
| Ranking | ClientId | CountryId | RegionId | LanguageId |
+---------+----------+-----------+----------+------------+
| 1 | NOT NULL | NOT NULL | NOT NULL | NOT NULL | 15
| 2 | NOT NULL | NULL | NOT NULL | NOT NULL | 13
| 3 | NOT NULL | NOT NULL | NULL | NOT NULL | 11
| 4 | NOT NULL | NULL | NULL | NOT NULL | 9
| 5 | NOT NULL | NOT NULL | NOT NULL | NULL | 7
| 6 | NOT NULL | NULL | NOT NULL | NULL | 5
| 7 | NOT NULL | NULL | NULL | NULL | 1
+---------+----------+-----------+----------+------------+
Run Code Online (Sandbox Code Playgroud)
我刚刚更新了此内容,以确保您通过空选项获得非空版本。
如果您编辑结果以返回比前 1 个更多的内容,您可以看到按正确顺序排列的项目。即,如果将语言从 2 更改为 1,您将在 1,1,1,Null 选项上获得 1,1,1,1 行
| 归档时间: |
|
| 查看次数: |
89 次 |
| 最近记录: |