无法使LEFT JOIN正常工作

时间:2014-11-26 10:00:58

标签: sql-server join

我有一个以下形式的SQL表:

TimeStamp   OeprationID MachineID   MachineOSVersion
xxx           1         MAC1        Vista
xxx           2         MAC2        Linux
xxx           3         MAC2        Linux
xxx           4         MAC3        MACOS

订阅信息可用:

SubscriptionID  MachineID
SUB1            MAC1
SUB2            MAC2
SUB3            MAC3
SUB3            MAC3
SUB3            MAC3

我想使用LEFT JOIN来实现一个表,它给出了这样的结果:

MachineID   MachineOSVersion Subscription
MAC1        Vista            SUB1
MAC2        Linux            SUB2
MAC3        MACOS            SUB3

操作表包含一个MachineOSVersion,我想将其与机器和订阅详细信息一起显示。涉及的领域较多,但仅限于样本。

编辑: 原始问题的变化:订阅表有多个MachineID,对于每个机器MachineID,我想在Operations表中查找并找出可用的“最新”MachineOSVersion。由于机器OS可以升级,因此可能会从较旧的日期更改为较晚的日期。因此,必须挑选最新的。

我在使用左连接时遇到的问题是我看到生成了多个重复项。可能是因为操作表中有很多机器机器ID?

5 个答案:

答案 0 :(得分:1)

我只会使用常规INNER JOINGROUP结果来获取所需的输出,并在INNER JOIN上添加一个子查询,以确保您获得最新的MachineOSVersion

子查询获得最大MachineOSVersion的每台机器的最后OperationId,但如果需要,您可以使用另一个字段,可能是时间戳。

SQL Fiddle Demo

MS SQL Server 2012架构设置

CREATE TABLE MachineTable
    (
      [TimeStamp] VARCHAR(3) ,
      [OperationID] INT ,
      [MachineID] VARCHAR(4) ,
      [MachineOSVersion] VARCHAR(6)
    );

INSERT  INTO MachineTable
        ( [TimeStamp], [OperationID], [MachineID], [MachineOSVersion] )
VALUES  ( 'xxx', 1, 'MAC1', 'Vista' ),
        ( 'xxx', 2, 'MAC2', 'Linux1' ),
        ( 'xxx', 3, 'MAC2', 'Linux2' ),
        ( 'xxx', 4, 'MAC3', 'MACOS' );

CREATE TABLE SubscriptionsTable
    (
      [SubscriptionID] VARCHAR(4) ,
      [MachineID] VARCHAR(4)
    );

INSERT  INTO SubscriptionsTable
        ( [SubscriptionID], [MachineID] )
VALUES  ( 'SUB1', 'MAC1' ),
        ( 'SUB2', 'MAC2' ),
        ( 'SUB3', 'MAC3' ),
        ( 'SUB3', 'MAC3' ),
        ( 'SUB3', 'MAC3' );

查询1

SELECT  st.MachineId ,
        st.SubscriptionId ,
        mt.MachineOSVersion,
        mt.OperationID
FROM    SubscriptionsTable st
INNER JOIN MachineTable mt ON mt.MachineId = st.MachineId 
      AND mt.OperationID = (SELECT MAX(mt2.OperationID) 
                            FROM MachineTable mt2
                            WHERE mt2.MachineId = mt.MachineId)
GROUP BY st.MachineId ,
        st.SubscriptionId ,
        mt.MachineOSVersion,
        mt.OperationID

<强> Results

| MACHINEID | SUBSCRIPTIONID | MACHINEOSVERSION | OPERATIONID |
|-----------|----------------|------------------|-------------|
|      MAC1 |           SUB1 |            Vista |           1 |
|      MAC2 |           SUB2 |           Linux2 |           3 |
|      MAC3 |           SUB3 |            MACOS |           4 |

答案 1 :(得分:0)

{{2p>'操作'应该是'操作'?

答案 2 :(得分:0)

SELECT MachineID, MachineOSVersion,       SubscriptionID AS Subscription
FROM Table1name AS op
LEFT OUTER JOIN Table2name AS sub
ON sub.MachineID = op.MachineID
ORDER BY MachineID

使用LEFT OUTER JOIN非常重要,因为这比LEFT JOIN&#39;更符合要求。 (它更有可能跨不同类型的数据库工作)

答案 3 :(得分:0)

试试这个。从distinct rows表中找到Subscription,然后在Left join中找到与其他表格对应的结果。

SELECT SubscriptionID,
       MachineOSVersion,
       A.MachineID
FROM   (SELECT DISTINCT SubscriptionID,
                        MachineID
        FROM   Subscription) A
       LEFT JOIN operation B
              ON A.MachineID = B.MachineID 

更新

从Operation表中获取最新一行。使用Window functionOperation表中获取最新行。

WITH cte
     AS (SELECT Row_number()OVER (partition BY [TimeStamp], [MachineID] ORDER BY [OeprationID] DESC) rn,
                *
         FROM   operation)
SELECT SubscriptionID,
       MachineOSVersion,
       A.MachineID
FROM  (SELECT [TimeStamp],[OeprationID],[MachineID],[MachineOSVersion]
       FROM   cte
       WHERE  rn = 1) A
      RIGHT JOIN (SELECT DISTINCT SubscriptionID,MachineID
                  FROM   SubscriptionsTable) B
              ON A.MachineID = B.MachineID 

答案 4 :(得分:0)

只是另一种始终获得最新价值的解决方案

SELECT
  st.MachineID,
  st.SubscriptionID
  (SELECT TOP 1 mt.MachineOSVersion FROM MachineTable mt 
   WHERE mt.MachineID = st.MachineID ORDER BY mt.TimeStamp DESC)
FROM
  (SELECT distinct(sti.MachineID),sti.SubscriptionID FROM SubscriptionsTable sti) st;

select(下面的查询)中的子查询将始终根据时间戳获取最新版本。这可能是一个更好的方法,然后继续操作id,因为operationid可能并不总是给出正确的顺序(例如,某些分布式数据库不保证主键始终完全按照正确的顺序)

  (SELECT TOP 1 mt.MachineOSVersion FROM MachineTable mt 
   WHERE mt.MachineID = st.MachineID ORDER BY mt.TimeStamp DESC) 
  -- Gets the latest machine os version of a system, done by 
  -- selecting the last entry based on the timestamp

在FROM表中,我们选择不同的机器ID以消除任何重复的机器ID。

(SELECT distinct(sti.MachineID),sti.SubscriptionID FROM SubscriptionsTable sti) st;

示例sqlfiddle

小提琴的DDL:     CREATE TABLE MachineTable         (           [TimeStamp] INT,           [OperationID] INT,           [MachineID] VARCHAR(10),           [MachineOSVersion] VARCHAR(10)         );

INSERT  INTO MachineTable
        ( [TimeStamp], [OperationID], [MachineID], [MachineOSVersion] )
VALUES  ( 1415616586, 1, 'MAC1', 'Vista' ),
        ( 1416480586, 2, 'MAC2', 'Linux v1' ),
        ( 1416912586, 3, 'MAC2', 'Linux v2' ),
        ( 1416998987, 4, 'MAC3', 'MACOS' );

CREATE TABLE SubscriptionsTable
    (
      [SubscriptionID] VARCHAR(4) ,
      [MachineID] VARCHAR(4)
    );

INSERT  INTO SubscriptionsTable
        ( [SubscriptionID], [MachineID] )
VALUES  ( 'SUB1', 'MAC1' ),
        ( 'SUB2', 'MAC2' ),
        ( 'SUB3', 'MAC3' ),
        ( 'SUB3', 'MAC3' ),
        ( 'SUB3', 'MAC3' );

小提琴的SQL查询:

SELECT
  st.MachineID,
  st.SubscriptionID,
  (SELECT TOP 1 mt.MachineOSVersion FROM MachineTable mt WHERE mt.MachineID = st.MachineID ORDER BY mt.TimeStamp DESC)
FROM
  (SELECT distinct(sti.MachineID),sti.SubscriptionID FROM SubscriptionsTable sti) st;

注意:DDL基于Tanner的DDL。