[英]JOIN statement on an alias - SQL Server
我正在寻找有关使用别名而不是原始数据加入的最佳方式的建议。 例如,数据在加入之前被修改。
一个例子:
CREATE TABLE Table1 (
No1 varchar(10)
);
CREATE TABLE Table2 (
No1 varchar(10)
);
INSERT INTO Table1 (No1)
VALUES ('222');
INSERT INTO Table2 (No1)
VALUES ('111');
如果我创建了一个带有case语句的连接但我想加入case语句的别名,这不适用于通常的连接语法,例如
SELECT
CASE WHEN T1.[No1] = '222' THEN '111' ELSE T1.[No1] END AS [T1 No],
T2.[No1] AS [T2 No]
FROM Table1 T1
FULL JOIN Table2 T2
ON T1.[No1] = T2.[No1]
这给出了结果:
| T1 No | T2 No |
|--------+--------|
| 111 | (null) |
| (null) | 111 |
http://www.sqlfiddle.com/#!18/203e8/1
但是,我加入别名的方法是:
SELECT
T1.[T1 No],
T2.[No1] AS [T2 No]
FROM
(
SELECT
CASE WHEN T1.[No1] = '222' THEN '111' ELSE T1.[No1] END AS [T1 No]
FROM Table1 T1
) T1
JOIN Table2 T2
ON T1.[T1 No] = T2.[No1]
这给出了结果:
| T1 No | T2 No |
|-------+-------|
| 111 | 111 |
http://www.sqlfiddle.com/#!18/5fd7c/14
这正是我要找的。 但是,我正在处理的现实生活中的查询是巨大的,并且查询它加入别名会使它变得如此混乱。
任何人都可以就更好的方法给我建议吗? 或者这是唯一的方法吗?
好的,首先,您可能知道SELECT语句的逻辑处理顺序 。 具体来说,该顺序是:
请注意, SELECT
是第8个要处理的内容,即处理列的别名时。 这意味着你不能在步骤9( DISTINCT
)之前引用列别名,这实际上意味着你在ORDER BY
这样做了,就是这样。
因此,如果要引用由表达式派生的列,则几乎没有这样做的方法,我在下面列出了一些方法。
第一种方式:
在SELECT
和ON
子句中使用Expression。 从而:
SELECT CASE WHEN T1.[No1] = '222' THEN '111'
ELSE T1.[No1]
END AS [T1 No],
T2.[No1] AS [T2 No]
FROM Table1 T1
JOIN Table2 T2 ON CASE WHEN T1.[No1] = '222' THEN '111'
ELSE T1.[No1]
END = T2.[No1];
这可能会使事情有点混乱,因为它可以使查询“忙”。
第二种方式:
使用子选择:
SELECT [T1 No]
FROM (SELECT CASE WHEN T1.[No1] = '222' THEN '111'
ELSE T1.[No1]
END AS [T1 No],
FROM Table1 T1) AS Tsq1
JOIN Table2 T2 ON Tsq1.[T1 No] = T2.[No1];
第三种方式
这与使用CTE的最后一个选项基本相同
WITH T1 AS (
SELECT CASE WHEN T1.[No1] = '222' THEN '111'
ELSE T1.[No1]
END AS [T1 No],
FROM Table1 T1)
SELECT [T1 No]
FROM T1
JOIN Table2 T2 ON T1.[T1 No] = T2.[No1];
第四种方式:
您还可以创建一个VIEW
,然后JOIN
:
CREATE VIEW Table1_vw AS
SELECT *,
SELECT CASE WHEN T1.[No1] = '222' THEN '111'
ELSE T1.[No1]
END AS [T1 No]
FROM Table1 T1;
GO
SELECT T1.[T1 No]
FROM Table1_vw T1
JOIN Table2 T2 ON T1.[T1 No] = T2.[No1];
这些只是几个选项,但希望能让您走上适合您自己需求的正确道路。
正如HoneyBadger所说。 在Select和ON状态下使用CASE Both
SELECT CASE WHEN T1.[No1] = '222' THEN '111' ELSE T1.[No1] END AS [T1 No],
T2.[No1] AS [T2 No]
FROM Table1 T1
JOIN Table2 T2
ON CASE WHEN T1.[No1] = '222' THEN '111' ELSE T1.[No1] END = T2.[No1];
问题是您无法使用别名,因为SELECT的执行顺序
正如您在此处可以看到SQL查询的执行顺序
JOIN在SELECT创建别名之前发生
作为变体,您可以使用辅助表
CREATE TABLE Link(
Table1_No1 varchar(10),
Table2_No1 varchar(10),
PRIMARY KEY(Table1_No1),
UNIQUE(Table1_No1,Table2_No1)
)
INSERT Link(Table1_No1,Table2_No1)VALUES
('222','111'),
('444','333'),
...
然后是一个查询
SELECT
T1.No1 [T1 No],
T2.No1 [T2 No]
FROM
(
SELECT ISNULL(L.Table2_No1,T1.No1) No1
FROM Table1 T1
LEFT JOIN Link L ON L.Table1_No1=T1.No1
) T1
JOIN Table2 T2 ON T1.No1=T2.No1
这种方式很有用,因为您不需要为新条件重写查询。
如果这个变体适合你,你可以写得更短
SELECT
ISNULL(L.Table2_No1,T1.No1) [T1 No],
T2.No1 [T2 No]
FROM Table1 T1
LEFT JOIN Link L ON L.Table1_No1=T1.No1
JOIN Table2 T2 ON T2.No1=ISNULL(L.Table2_No1,T1.No1)
如果您想避免多次编写表达式,那么唯一的选择是在将表达式指定为别名后加入(并且连接必须位于最外层范围内,因此它被视为表格)。 如果问题是整洁,我总是发现使用CTE比FROM
subquery更具可读性。
;WITH ComplexQueryCalculations AS
(
SELECT
ID = T.ID,
SomeColumn = T.SomeColumn,
ExpressionResult = CASE
WHEN T.PlanetsAlign = 1 AND X.OtherColumn > 100
THEN (N.OtherColumn * 100) / NULLIF(N.AnotherColumn, 0)
ELSE
N.OtherColumn END
FROM
Table1 AS T
INNER JOIN Table2 AS N ON T.SomeColumn = N.SomeColumn
LEFT JOIN Table3 AS X ON
T.SomeColumn = CONVERT(INT, X.SomeColumn) AND
N.SomeColumn = X.OtherColumn
WHERE
T.ID <= 15000 AND
CHARINDEX('_', T.SomeColumn) > 1 AND
(
T.SomeColumn <> 'Property' OR
(T.SomeColumn = 'Property' AND X.SomeColumn BETWEEN 1 AND 100)
)
),
FilteredExpressionResult AS
(
SELECT
C.ID,
C.SomeColumn,
C.ExpressionResult
FROM
ComplexQueryCalculations AS C -- Reference previous CTE
WHERE
C.ExpressionResult >= 50 -- Filter the alias!
)
SELECT
F.*
FROM
FilteredExpressionResult AS F
INNER JOIN YetAnotherTable AS Y ON F.ID = Y.ID
WHERE
Y.SomeColumn IS NOT NULL
您可以将子查询分开,为它们提供适当的间距和表别名,并通过在中间创建临时表或变量表来为正在阅读正确查询顺序的人提供,而无需花费资源。
我不确定你为什么使用full join
而不是inner join
。 但另一种解决方案是使用apply
:
SELECT . . .
FROM Table1 T1 CROSS APPLY
(VALUES (CASE WHEN T1.[No1] = '222' THEN '111' ELSE T1.[No1] END)
) V([T1 No]) JOIN
Table2 T2
ON V.[T1 No] = T2.[No1];
APPLY
可以方便地添加计算列。 您不需要子查询或CTE。 对查询的更改很少。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.