[英]JOIN statement on an alias - SQL Server
I am looking for advice on the best way to join using an alias instead of the original data. 我正在寻找有关使用别名而不是原始数据加入的最佳方式的建议。 eg the data is modified before it is joined.
例如,数据在加入之前被修改。
An example: 一个例子:
CREATE TABLE Table1 (
No1 varchar(10)
);
CREATE TABLE Table2 (
No1 varchar(10)
);
INSERT INTO Table1 (No1)
VALUES ('222');
INSERT INTO Table2 (No1)
VALUES ('111');
If i created a join with a case statement but i wanted to join on the alias of the case statement this doesnt work with usual join syntax eg 如果我创建了一个带有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]
This gives result: 这给出了结果:
| T1 No | T2 No |
|--------+--------|
| 111 | (null) |
| (null) | 111 |
http://www.sqlfiddle.com/#!18/203e8/1 http://www.sqlfiddle.com/#!18/203e8/1
However, the approach i have taken to join on the alias is: 但是,我加入别名的方法是:
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]
This gives result: 这给出了结果:
| T1 No | T2 No |
|-------+-------|
| 111 | 111 |
http://www.sqlfiddle.com/#!18/5fd7c/14 http://www.sqlfiddle.com/#!18/5fd7c/14
Which is exactly what i am looking for. 这正是我要找的。 However, the real life query i am dealing with is huge and sub-querying it to join on an alias makes it so messy.
但是,我正在处理的现实生活中的查询是巨大的,并且查询它加入别名会使它变得如此混乱。
Can anyone give me advice on a better approach to this? 任何人都可以就更好的方法给我建议吗? or is this the only way to do it?
或者这是唯一的方法吗?
Ok, firstly, it's probably good for you to be aware of the Logical Processing Order of the SELECT statement . 好的,首先,您可能知道SELECT语句的逻辑处理顺序 。 Specifically, that order is:
具体来说,该顺序是:
Notice that that SELECT
is the 8th thing to be processed, which is when the alias of a column would be processed. 请注意,
SELECT
是第8个要处理的内容,即处理列的别名时。 This means you can't reference a columns alias until step 9 ( DISTINCT
), which really means your left with doing so in the ORDER BY
and that's it. 这意味着你不能在步骤9(
DISTINCT
)之前引用列别名,这实际上意味着你在ORDER BY
这样做了,就是这样。
Thus, if you want to reference a column that is derived by an expression, you have few ways of doing so, some I have listed below. 因此,如果要引用由表达式派生的列,则几乎没有这样做的方法,我在下面列出了一些方法。
1st way: 第一种方式:
Use the Expression in the SELECT
and the ON
clause. 在
SELECT
和ON
子句中使用Expression。 Thus: 从而:
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];
This can make things a little confusing, as it can make the query "busy". 这可能会使事情有点混乱,因为它可以使查询“忙”。
2nd way: 第二种方式:
Use a Subselect: 使用子选择:
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];
3rd way 第三种方式
This is basically the same as the last option, however, using a CTE 这与使用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];
4th Way: 第四种方式:
You also could create a VIEW
, and then JOIN
on that: 您还可以创建一个
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];
These are just a few options, but hopefully that puts you on the right path for what works for your own needs. 这些只是几个选项,但希望能让您走上适合您自己需求的正确道路。
As HoneyBadger said. 正如HoneyBadger所说。 Use the CASE Both in the Select and on the ON condition
在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];
The problem is you cant use the alias because the execution order of the SELECT 问题是您无法使用别名,因为SELECT的执行顺序
As you can see here Order Of Execution of the SQL query 正如您在此处可以看到SQL查询的执行顺序
The JOIN happen before the SELECT create the alias JOIN在SELECT创建别名之前发生
As variant you can use an auxiliary table 作为变体,您可以使用辅助表
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'),
...
And then a query 然后是一个查询
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
This way is useful because you don't need rewrite your query for new conditions. 这种方式很有用,因为您不需要为新条件重写查询。
And if this variant suits you, you can write it more shorter 如果这个变体适合你,你可以写得更短
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)
If you want to avoid writing your expressions multiple times, then the only option is joining after asigning the expression to an alias (and the join must be in an outmost scope, so it's treated like a table). 如果您想避免多次编写表达式,那么唯一的选择是在将表达式指定为别名后加入(并且连接必须位于最外层范围内,因此它被视为表格)。 If the problem is the tidiness, I always find using CTEs a lot more readable than subquerying in the
FROM
. 如果问题是整洁,我总是发现使用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
You can keep your subqueries separated, give them proper spacing and table alias, and give the person who is reading a proper query order, without spending resources by creating temporary or variable tables in the middle. 您可以将子查询分开,为它们提供适当的间距和表别名,并通过在中间创建临时表或变量表来为正在阅读正确查询顺序的人提供,而无需花费资源。
I'm not sure why you are using full join
rather than inner join
. 我不确定你为什么使用
full join
而不是inner join
。 But another solution is to use apply
: 但另一种解决方案是使用
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
can be handy for adding in computed columns. APPLY
可以方便地添加计算列。 You don't need subqueries or CTEs. 您不需要子查询或CTE。 The changes to the query are minimal.
对查询的更改很少。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.