SQL Server Top 1

6
在 Microsoft SQL Server 2005 或更高版本中,我想要获取第一行,如果没有匹配的行,则返回一行带有默认值的内容。
SELECT TOP 1 ID,Name
FROM TableName
UNION ALL 
SELECT 0,''
ORDER BY ID DESC

这个代码可以正常运行,但是如果表中有数据,它会返回两行,没有数据则返回1行。我希望它始终只返回1行。我认为问题与 EXISTS 有关,但不确定。可能需要这样修改:

SELECT TOP 1 * FROM Contact 
WHERE EXISTS(select * from contact)

但如果不存在,则选择0,''

5个回答

7
当表非常满时,你可能需要指定你想要获取的顶部1行的哪一行,比如第一个名字。如果你只是改变ORDER BY子句,OMG Ponies的查询将在这种情况下返回错误答案。他的查询也比这个修改多花费约8%的CPU(尽管它具有相等的读取量)。
SELECT TOP 1 *
FROM (
   SELECT TOP 1 ID,Name
   FROM TableName
   ORDER BY Name
   UNION ALL
   SELECT 0,''
) X
ORDER BY ID DESC

区别在于内部查询也有一个TOP 1,并且可以在那里指定哪个 TOP 1(如所示)。
只是为了好玩,这是另一种方法,它的性能非常接近上面的查询(-15ms到+30ms)。虽然对于这样一个简单的查询来说比必要的更加复杂,但它演示了一种我不经常看到其他SQL专家使用的技术。
SELECT
   ID = Coalesce(T.ID, 0),
   Name = Coalesce(T.Name, '')
FROM
   (SELECT 1) X (Num)
   LEFT JOIN (
      SELECT TOP 1 ID, Name
      FROM TableName
      ORDER BY ID DESC
   ) T ON 1 = 1 -- effective cross join but does not limit rows in the first table

5

使用:

  SELECT TOP 1
         x.id,
         x.name
    FROM (SELECT t.id,
                 t.name
            FROM TABLENAME t
          UNION ALL
          SELECT 0, 
                 '') x
ORDER BY id DESC

使用等价的CTE:

WITH query AS (
    SELECT t.id,
           t.name
      FROM TABLENAME t
    UNION ALL
    SELECT 0, 
           '')
  SELECT TOP 1
         x.id,
         x.name
    FROM query x
ORDER BY x.id DESC

2
CREATE TABLE #sample(id INT, data VARCHAR(10))

SELECT TOP 1 id, data INTO #temp FROM #sample
IF @@ROWCOUNT = 0 INSERT INTO #temp VALUES (null, null)
SELECT * FROM #temp

3
如果用户指定为(0,''),而不是(NULL, NULL),那么这将起作用。但是需要进行大量的工作/数据库处理来创建和插入到临时表中,将TOP 1放在派生表之外并使用UNION的方法要高效得多。如果在频繁使用的生产环境中出现这种情况,将会非常糟糕。 - KM.
使用临时表比其他方法多约200次读取。让人们知道这是可能的是好的,但我认为在任何人的列表上,使用临时表应该是最后一个选择。 - ErikE

1
IF EXISTS ( SELECT TOP 1 ID, Name FROM TableName )
 BEGIN
     SELECT TOP 1 ID, Name FROM TableName
 END
ELSE
 BEGIN
 --exists returned no rows
 --send a default row
 SELECT 0, ''
 END

1
选择数据两次并不高效,一次在IF中,另一次为结果集。此外,在TSQL中,单行注释是“--”,多行注释是“/”后跟“/”,而不是像VB中的单引号“'”。 - KM.
1
抱歉,我之前使用的是 VB.NET。我在帮助你的过程中意识到了 --comment 和 /comment/ 都是可以编辑的。 - JonH
1
@KM:他并没有真正“选择两次数据”。EXISTS查询与常规查询的工作方式不同。虽然我同意这种方法效率较低,但是在这里使用EXISTS的成本只有读取一次或三次,无论表格有多满。 - ErikE
1
为了清晰起见,请编辑您的帖子,将其更改为IF EXISTS(SELECT 1 FROM TableName),而不是复制查询(这可能会使人们感到困惑,特别是其中含有无意义的TOP)。 - ErikE

1
将顶部放在 UNION 查询之外。
SELECT TOP 1 * FROM(
SELECT  ID,Name
FROM TableName
UNION ALL 
SELECT 0,''
) z
ORDER BY ID DESC

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