在Microsoft tSQL中,如果没有找到行,则返回一个值

123

我使用的是 Microsoft 版本的 SQL,这是我的一个简单查询。如果我查询的记录不存在,则不会返回任何结果。我希望在这种情况下返回 false (0)。寻找最简单的方法来处理没有记录的情况。

SELECT  CASE
            WHEN S.Id IS NOT NULL AND S.Status = 1 AND (S.WebUserId = @WebUserId OR S.AllowUploads = 1) THEN 1
            ELSE 0
        END AS [Value]

        FROM Sites S

        WHERE S.Id = @SiteId

实际上,这可能会更容易。请参见下面的答案 - Weihui Guo
16个回答

153

这与Adam Robinson的方法相似,但使用ISNULL代替COUNT。

SELECT ISNULL(
(SELECT 1 FROM Sites S
WHERE S.Id = @SiteId and S.Status = 1 AND 
      (S.WebUserId = @WebUserId OR S.AllowUploads = 1)), 0)

如果内部查询有匹配的行,则返回1。然后外部查询(使用 ISNULL)返回值为1。如果内部查询没有匹配的行,则不返回任何内容。外部查询将其视为 NULL,因此 ISNULL 返回 0。


2
谢谢您添加这个!这正是我所需要的,因为我可以只需选择ISNULL((SELECT Id ...而不是1来获取我要查找的数据! - Jesse Smith
4
虽然有些晚,但你可以使用COALESCE代替ISNULL来获得相同的结果。 - BlueChippy
2
我已经养成了使用COALESCE而不是ISNULL的习惯,因为从记忆中(习惯难改),ISNULL在SQL Lite或运行在旧Windows Mobile设备上的其它名称中不可用。COALESCE适用于lite、Express和完整版SQL。 - Ads
1
如果你想获取变量的值,最好使用它的实际值,而不是0或1。Adam的查询需要分组或类似的操作。 - Arseniy
1
@Michael - 你可以使用"SELECT S.YourRequiredColumnName"代替"SELECT 1"。 - Moe Sisko
显示剩余3条评论

75
SELECT CASE WHEN COUNT(1) > 0 THEN 1 ELSE 0 END AS [Value]

FROM Sites S

WHERE S.Id = @SiteId and S.Status = 1 AND 
      (S.WebUserId = @WebUserId OR S.AllowUploads = 1)

以下查询返回else条件中的单个值,但理想情况下它应该返回多个值。选择 CASE WHEN COUNT(QTIB_REQ_) < 1 THEN 0 ELSE QTIB_REQ_ END FROM qb_requisitions_all WHERE QTIB_REQ_ IN ($Req_disabled_WA) AND CLIENT___BENCH___NON_BILLABLE NOT IN ('Non Billable', 'Non-Billable', 'NonBillable', 'Bench', 'Bench - SC Cleared Strategic Hires', 'Bench/US project') AND DATEDIFF(CURDATE(), TARGET_FILL_DATE) < 60 AND DATEDIFF(CURDATE(), TARGET_FILL_DATE) > 0 - Praneet Bahadur

30

可能这已经是老生常谈了,当没有行存在时,另一种返回1行的方法是使用UNION连接另一个查询,并在表中不存在结果时显示它们。

SELECT S.Status, COUNT(s.id) AS StatusCount
FROM Sites S
WHERE S.Id = @SiteId
GROUP BY s.Status
UNION ALL --UNION BACK ON TABLE WITH NOT EXISTS
SELECT 'N/A' AS Status, 0 AS StatusCount
WHERE NOT EXISTS (SELECT 1
   FROM Sites S
   WHERE S.Id = @SiteId
) 

2
当我尝试从查询中获取总数时,我使用了类似的方法。我只是使用返回0的查询(SELECT 0)进行了联合,然后在联合上执行了SUM。简单易懂。 - cjbarth
2
如果返回2行,是否保证这些行将按预期顺序返回? - Sarsaparilla
1
而且它对执行计划有很大的影响。 - Fandango68

17

类似于:

if exists (select top 1 * from Sites S where S.Id IS NOT NULL AND S.Status = 1 AND (S.WebUserId = @WebUserId OR S.AllowUploads = 1))
    select 1
else
    select 0

我选择了这种解决方案,因为它对我来说更有意义(我传统上不是 SQL 用户)。然而,我正在使用 SQL Server,在这个解决方案中添加列名可以使其更完美。例如,在您的 select 1select 2 后面,我加上了 as <colName> - Harvey

12

我阅读了这里的所有答案,花费了一些时间才弄清楚发生了什么。以下内容基于 Moe Sisko 的回答以及相关研究。

如果你的SQL查询没有返回任何数据,那么不会有一个具有null值的字段,因此ISNULL和COALESCE都不能按照你期望的方式工作。通过使用子查询,顶层查询将获得一个具有null值的字段,然后ISNULL和COALESCE将按照你想要或期望的方式工作。

我的查询

select isnull(
 (select ASSIGNMENTM1.NAME
 from dbo.ASSIGNMENTM1
 where ASSIGNMENTM1.NAME = ?)
, 'Nothing Found') as 'ASSIGNMENTM1.NAME'

我的带有注释的查询

select isnull(
--sub query either returns a value or returns nothing (no value)
 (select ASSIGNMENTM1.NAME
 from dbo.ASSIGNMENTM1
 where ASSIGNMENTM1.NAME = ?)
 --If there is a value it is displayed 
 --If no value, it is perceived as a field with a null value, 
 --so the isnull function can give the desired results
, 'Nothing Found') as 'ASSIGNMENTM1.NAME'

6

您只需将WHERE替换为LEFT JOIN:

SELECT  CASE
        WHEN S.Id IS NOT NULL AND S.Status = 1 AND ...) THEN 1
        ELSE 0
    END AS [Value]

    FROM (SELECT @SiteId AS Id) R
    LEFT JOIN Sites S ON S.Id = R.Id

这个解决方案允许你为每一列返回默认值,例如:

SELECT
    CASE WHEN S.Id IS NULL THEN 0 ELSE S.Col1 END AS Col1,
    S.Col2,
    ISNULL(S.Col3, 0) AS Col3
FROM
    (SELECT @Id AS Id) R
    LEFT JOIN Sites S ON S.Id = R.Id AND S.Status = 1 AND ...

6
这可能是一种方法。
SELECT TOP 1 [Column Name] FROM (SELECT [Column Name] FROM [table]
    WHERE [conditions]
    UNION ALL
    SELECT 0 )A ORDER BY [Column Name] DESC

我喜欢这种方法。我觉得它在表达默认数据时更加清晰,特别是当你最终拥有大量的数据/默认值列时。 - Mark At Ramp51
这是最好的、最干净的解决方案。 - Kyle Bridenstine
在许多情况下,这更加灵活。 - Paul Sturm

3

“No record matched”意味着没有记录返回。如果没有找到记录,就没有“value”为0的位置。您可以创建一个疯狂的UNION查询来实现您想要的功能,但更好的方法是检查结果集中的记录数。


目前,这就是我所做的。检查记录计数是否为空。想到可能有一种方式来简化我的检查。 - Matt
一些应用程序不允许你“简单地”检查。 - Nadia Solovyeva

3
DECLARE @col int; 
select @col = id  FROM site WHERE status = 1; 
select coalesce(@col,0);

2
@hai-phan的答案使用了LEFT JOIN是关键,但有点难以理解。我有一个复杂的查询,可能也会返回空。我只是根据我的需要简化了他的答案。它很容易应用于具有许多列的查询。
;WITH CTE AS (
  -- SELECT S.Id, ...
  -- FROM Sites S WHERE Id = @SiteId
  -- EXCEPT SOME CONDITION.
  -- Whatever your query is
)
SELECT CTE.* -- If you want something else instead of NULL, use COALESCE.
FROM (SELECT @SiteId AS ID) R
LEFT JOIN CTE ON CTE.Id = R.ID

更新:SqlServerCentral 上的这个答案是最好的。它利用了 MAX 的这个特性 - “当没有行可选择时,MAX 返回 NULL。”
SELECT ISNULL(MAX(value), 0) FROM table WHERE Id = @SiteId

1
ISNULL(MAX(value), 0) 对我来说可行。 - GinCanhViet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接