问题 我可以在T-SQL SELECT中定义一个循环变量(比如LINQ中的LET)吗?


我可以用LINQ写这样的东西:

var selection = from person in personList
                let initials = person.FirstName[0] + person.LastName[0]
                select initials;

我可以用SQL做类似的事情,比如:

SELECT @Initials
FROM [Person]
SET @Initials = SUBSTRING (Person.FirstName, 1, 1) + SUBSTRING (Person.LastName, 1, 1)

可能不是,但也许有一个伎俩?

我需要有一个预先计算的变量,以便在复杂的WHERE子句中进一步使用,以避免极端复杂性和代码重复。


9322
2018-06-05 14:24


起源

不要将“t-sql”用于标记 - 请改用“tsql”。在标记问题时请注意建议提示 - 应该避免使用名称后面的数字<10的任何标记。 - Joel Coehoorn
为什么?通常使用“T-SQL”但不使用TSQL。 - User
@Mastermind,不幸的是更多的人历史上使用tsql,所以我们重新标记为一致性。 - Cade Roux
因为stackoverflow上有1021个问题标记为'tsql'而没有其他问题标记为't-sql'。您认为哪个标签更受欢迎?添加标签时请注意提示。 - Joel Coehoorn
或者,如果您真的想重新标记超过1000个问题,请成为我的客人。 - Joel Coehoorn


答案:


在不添加临时表,循环等的情况下执行此操作的干净方法将使用公用表表达式(CTE)。例:

;WITH PersonsWithInitials AS
(
    SELECT
        SUBSTRING (COALESCE(Person.FirstName,''), 1, 1)
        + SUBSTRING (COALESCE(Person.LastName,''), 1, 1) AS Initials,            
        FirstName,
        LastName,
        City
    FROM
        [Person]
)
SELECT
    FirstName,
    LastName,
    City,
    Initials
FROM
    PersonsWithInitials
WHERE
    /* Complex WHERE clause goes here and it can reference Initials as if it were a field */

代替上面的空“”,您可以使用句号或其他内容代替空名称字段。

这应该都是在.NET的单个SQL调用中执行的 - CTE不会像视图,存储过程,临时表等一样保存在数据库中。


12
2018-06-05 14:25



需要测试NULL情况 - van
OP说:“我需要一个预先计算的变量,以便在复杂的WHERE子句中进一步使用”。从他们的问题来看,看起来他们想要将结果存储在变量中,而不仅仅是返回一次性结果集。如果没有,那么这是一个很好的答案,否则他们需要检查我的答案...... - KM.
-1如果我理解他,这不是op所要求的。 - JoshBerke


看起来你只是想把首字母变成一个变量供以后使用。试试这种方式......

DECLARE @Initials varchar(2)

SELECT @Initials = SUBSTRING (Person.FirstName, 1, 1) + SUBSTRING (Person.LastName, 1, 1)
FROM   [Person]
WHERE  ....

如果您尝试将其用作集合而不是单个值,则应该查看使用其他复杂查询执行子查询或CTE。


3
2018-06-05 14:37





SELECT Initials
    = SUBSTRING (Person.FirstName, 1, 1)
      + SUBSTRING (Person.LastName, 1, 1)
FROM [Person]

要么

SELECT SUBSTRING (Person.FirstName, 1, 1) 
       + SUBSTRING (Person.LastName, 1, 1)
            AS Initials
FROM [Person]

如果以后需要使用它,一个清晰可读的方法是使用公共表exprssion(可以堆叠,而不是嵌套):

WITH Person2 AS (
    SELECT SUBSTRING (Person.FirstName, 1, 1) 
           + SUBSTRING (Person.LastName, 1, 1)
                AS Initials
    FROM [Person]
)
SELECT Initials, COUNT(*) AS Record_Count
FROM Person2
GROUP BY Initials

2
2018-06-05 14:26





如果要保留一组首字母以便多次使用,或者作为较大查询的一部分,请执行以下操作:

declare @TableVariable  table (Initials varchar(200)

INSERT INTO @TableVariable  
        (Initials)
    SELECT
        ISNULL(SUBSTRING(Person.FirstName,1,1),'')+ISNULL(SUBSTRING(Person.LastName,1,1),'')
    FROM Person

SELECT * FROM @TableVariable

SELECT * FROM @TableVariable

如果你做了很多行#temp表更快。此外,在比使用临时表更大的查询中使这个派生表更快可能会更快。


-1
2018-06-05 15:08



如果OP的查询过滤的不仅仅是首字母,那么表变量可能会严重影响性能。在大多数情况下,CTE会更好,因为它使用基础表的索引(表变量不是)。 - richardtallent
@richardtallent,阅读问题和我的答案!我说“如果你想保留一组首字母来多次使用”。从OP的问题来看,他也试图将结果变成一个变量。你不能用CTE做到这一点。我只是建议一种不同类型的解决方案! - KM.