简体   繁体   English

别名上的JOIN语句 - SQL Server

[英]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: 具体来说,该顺序是:

  1. FROM
  2. ON
  3. JOIN 加入
  4. WHERE 哪里
  5. GROUP BY 通过...分组
  6. WITH CUBE or WITH ROLLUP WITH CUBE或WITH ROLLUP
  7. HAVING HAVING
  8. SELECT 选择
  9. DISTINCT 不同
  10. ORDER BY 订购
  11. TOP 最佳

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. SELECTON子句中使用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

SQL DEMO SQL DEMO

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM