【问题标题】:Stored procedure: Select by matching input parameter or return the null records存储过程:通过匹配输入参数选择或返回空记录
【发布时间】:2017-10-08 06:38:32
【问题描述】:

我有以下情况:

有一张这样的表:

Id     | Param  | Value
------ | ------ | -------------
1      | 1      | One 1
1      | NULL   | Null-Value 1
1      | 2      | Two 1
1      | 3      | Three 3
2      | NULL   | Nul-Value 2
2      | 2      | Two 2
3      | NULL   | Null-Value 3
4      | 1      | One 4
5      | NULL   | Null-Vaue  5
6      | NULL   | Null-Value 6

我必须编写一个存储过程,因为“Param”的给定输入可为空参数我必须生成一个结果,该结果将包含一个带有 ID 和值的表,结果基于逻辑 -

如果输入参数为空 - 返回所有参数为空值的行

如果参数不为空,则返回在 Param 列中与该参数匹配的行以及所有具有空值作为 Param 的行(对于其他 ID)。

每个 ID 必须只有一个结果

考虑在 Id 和 Param 列上应用了唯一复合索引。

示例:

Input parameter: 1

Output table:

Id | Value
-- | -------------
1  | One 1
2  | Nul-Value 2
3  | Null-Value 3
4  | One 4
5  | Null-Vaue  5
6  | Null-Value 6

示例 2(让我也包括 Param 列以提高可见性):

Input parameter: 2

Output table:

Id | Param | Value
-- | ----- |-------------
1  | 2     |Two 1
2  | 2     |Two 2
3  | NULL  |Null-Value 3
5  | NULL  |Null-Value 5
6  | NULL  |Null-Value 6

  • 我想这将是表与自身的连接,或者使用 cross(或者可能是外部)apply 和一些适当的 where 子句更好......

【问题讨论】:

  • 到目前为止你写了什么?你遇到了什么错误?
  • 类似这样:从 [dbo].[MyTable] 中选择 t.Id、t.MyParam、t.MyValue t 外部应用(从 MyTable t2 中选择 *,其中 t2.MyParam = @ input 和.Id = t2.Id and t.MyParam = t2.MyParam) mt where (mt.MyParam = @ input and t.MyParam is not null) or t.MyParam is null 但它也返回 Id 1 的 NULL 值(休息没问题)
  • 外部应用让我哭了。
  • 我们没有在标题中加上“SOLVED”。特别是当所选答案是如此糟糕时。 span>

标签: sql sql-server database tsql stored-procedures


【解决方案1】:

这解决了每个 id 有多个结果的问题。你没有给出任何你想要每个 id 的规则,所以我不能做下一步。

SELECT *
FROM tableyoudidnotsaythenameof as x
WHERE (coalesce(x.value, @inparam) = @inparam) or
      (@inparam is null and x.value is null)

如果您不在乎每个 id 有多个时返回哪一个,这将起作用:

SELECT * 
FROM (
  SELECT *, row_number() over (partition by id) as rn
  FROM tableyoudidnotsaythenameof as x
  WHERE (coalesce(x.value, @inparam) = @inparam) or
        (@inparam is null and x.value is null)
) zed
WHERE zed.rn = 1

对具有更大 rn 的空值进行排序:

  SELECT *, row_number() over (partition by id order by CASE WHEN x.value is null then 2 else 1 END) as rn

【讨论】:

  • 每个 id 应该只有一个结果,因为在 ID 和 Param 上应用了唯一索引,因此它将与作为 Pram 的 null 或与输入参数匹配。上面的例子不适用于不同于 1 和 null 的输入参数
  • @peev -- 肯定会的。你试过了吗?
  • 是的,我只是将表的名称替换为我的,而不是 x.value - x.param,并且我在 (partition by id) 中放了一个“order by id”,因为它是必填。
  • @peev -- 你期望 2 的输出是什么,这与你得到的有什么不同?
  • "返回与 Param 列中该参数匹配的行以及所有具有空值作为 Param 的行" - 返回具有 Param = @ inparam 和 Param = null 行的表.见上文,我已经更新了问题帖
【解决方案2】:

您可以在不使用连接的情况下使用这个。当@param 为空时,它返回所有行。

DECLARE @t TABLE (id INT, [Param] INT, Val VARCHAR(50))
INSERT INTO @t VALUES
(1, 1,' One 1'),
(1, NULL,'Null-Value 1'),
(1, 2,'Two 1'),
(1, 3,'Three 3'),
(2,NULL,'Nul-Value 2'),
(2, 2,'One 2'),
(3, NULL,'Null-Value 3'),
(4, 1,'One 4'),
(5, NULL,'Null-Vaue 5'),
(6, NULL,'Null-Value 6')

DECLARE @Param INT
SET @Param = 1

SELECT *
FROM @t
WHERE @Param IS NULL OR (([Param] = @Param) OR ([Param] IS NULL AND Id <> @Param))

【讨论】:

  • 如果@Param 为空,则返回所有行
【解决方案3】:

我想通了。这是查询:

declare @input int = 2

select t.Id, t.Value
from [dbo].[MyTable] t
outer apply (select * from MyTable t2
             where t2.Param = @input
             and t.Id = t2.Id) mt
where  (t.Id = mt.Id and t.Param = @input)
or (t.Param is null and mt.Param is null)

【讨论】:

    猜你喜欢
    • 2020-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-20
    • 1970-01-01
    • 1970-01-01
    • 2019-09-08
    相关资源
    最近更新 更多