【发布时间】:2015-08-27 12:56:01
【问题描述】:
我有一个名为ClientUrls 的表,其结构如下:
+------------+----------------+----------+
| ColumnName | DataType | Nullable |
+------------+----------------+----------+
| ClientId | INT | No |
| CountryId | INT | Yes |
| RegionId | INT | Yes |
| LanguageId | INT | Yes |
| URL | NVARCHAR(2048) | NO |
+------------+----------------+----------+
我有一个存储过程up_GetClientUrls,它采用以下参数:
@ClientId INT
@CountryId INT
@RegionId INT
@LanguageId INT
有关过程的信息
- 所有参数都是 proc 所必需的,它们都不会是 NULL
- proc 的目的是根据预定义的优先级返回表中的单个匹配行。优先级是 ClientId>Country>Region>Language
- ClientUrls 表中的三个列可以为空。如果一列包含 NULL,则表示“全部”。例如如果 LanguageId 为 NULL,则它指的是“AllLanguages”。因此,如果我们向 proc 发送一个 LanguageId 为 5 的值,我们会首先查找它,否则我们会尝试查找为 NULL 的那个。
优先级矩阵(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 |
+---------+----------+-----------+----------+------------+
这是一些示例数据:
+----------+-----------+----------+------------+-------------------------------+
| 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 |
+----------+-----------+----------+------------+-------------------------------+
存储过程调用示例
EXEC up_GetClientUrls @ClientId = 1
,@CountryId = 1
,@RegionId = 1
,@LanguageId = 2
预期响应(基于示例数据)
+----------+-----------+----------+------------+-------------------------------+
| ClientId | CountryId | RegionId | LanguageId | URL |
+----------+-----------+----------+------------+-------------------------------+
| 1 | 1 | NULL | 2 | http://www.Anotherwebsite.com |
+----------+-----------+----------+------------+-------------------------------+
返回此行是因为匹配具有正确 LanguageId 的 NULL RegionId 比匹配具有正确 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
【问题讨论】:
-
您的客户 ID 在表中是唯一的吗?我的意思是如果我能得到
[Client_id 1 Country 1], [client_id 1, country 2] -
ClientId、CountryId、RegionId和LanguageId都应该是唯一的(包括NULLS唯一)。
-
你使用
TOP 1我应该在你当前的代码中检查TOP 1 WITH TIES,因为不知道你的索引它不是那么明显。 -
您可以使用具有相同排列的 CASE 语句(即,第一个将是 CASE WHEN ClientID = @@ClientID AND CountryID = @@CountryID 等,等等。最后一个将有 3 个 IS NULL)。我认为你会有更好的表现,但我不确定。
标签: sql sql-server tsql stored-procedures