T-SQL加入“max”过滤器

时间:2017-05-17 22:14:27

标签: sql sql-server tsql join

我正在使用SQL Server 2014.

我希望以下内容不会给我任何重复的电话ID或号码:

WITH Phones as
(
    SELECT * FROM (VALUES 
    (1,'602 600 8000'),
    (2,'602 600 8001'),
    (3,'602 600 8002')
    ) AS Vict_t (Id,Number)
), InvoicePhones as
(
    SELECT * FROM (VALUES
    (10, 1, 100, 'Alpha'),
    (11, 1, 101, 'Bravo'),
    (12, 1, 102, 'Charlie'),
    (13, 2, 103, 'Alpha'),
    (14, 2, 104, 'Bravo'),
    (15, 2, 105, 'Charlie'),
    (16, 3, 106, 'Alpha'),
    (17, 3, 107, 'Bravo'),
    (18, 3, 108, 'Charlie')
    ) as ip_t (Id,PhoneId,VoiceId, Name)
), Voices as
(
    SELECT * FROM (VALUES
     (100, '201701'),
     (101, '201702'),
     (102, '201703'),
     (103, '201704'),
     (104, '201705'),
     (105, '201706'),
     (106, '201708'),
     (107, '201709'),
     (108, '201710')
    ) AS Voices_t (Id,BillingCycle)
)

SELECT P.Id PhoneId, P.Number, IP.Name
FROM Phones P
LEFT JOIN InvoicePhones IP on IP.PhoneId = P.Id and IP.VoiceId =
    (
    select TOP 1 id
    from Voices V
    where V.Id = IP.VoiceId
    order by V.BillingCycle desc
    )

我无法理解为什么子选择没有消除重复。

我收到的是:

1   602 600 8000    Alpha
1   602 600 8000    Bravo
1   602 600 8000    Charlie
2   602 600 8001    Alpha
2   602 600 8001    Bravo
2   602 600 8001    Charlie
3   602 600 8002    Alpha
3   602 600 8002    Bravo
3   602 600 8002    Charlie

我期待的是:

1   602 600 8000    Charlie
2   602 600 8001    Charlie
3   602 600 8002    Charlie

此示例使用简单的整数ID,但我正在使用的真实表使用 uniqueidentifier 。因此,我需要的答案必须考虑到这一点。

我尝试了这个accepted answer的两个版本,但它对我不起作用。

我错过了什么?

更新

除了我选择的答案之外,我意识到解决这个问题的另一种方法如下:

SELECT P.Id PhoneId, P.Number, IP.Name
FROM Phones P
LEFT JOIN InvoicePhones IP on IP.PhoneId = P.Id and IP.VoiceId =
    (
    select TOP 1 V.Id
    from Voices V
    INNER JOIN InvoicePhones IPS ON IPS.VoiceId = V.Id
    WHERE P.Id = IPS.PhoneId
    order by V.BillingCycle desc
    )

我很好奇他们是否也可以通过外部申请来解决,as mentioned in this other SO post

3 个答案:

答案 0 :(得分:0)

看起来您需要使用/来获取最新的ID,但最终的逻辑或对第三个表的需求并不明确。

<强> SQL DEMO

ROW_NUMBER()

<强>输出

enter image description here

包含第三个表格:

<强> SQL DEMO

), filter as (
    SELECT P.Id PhoneId, P.Number, IP.Name, IP.VoiceId,
           ROW_NUMBER() OVER (PARTITION BY P.Id ORDER BY VoiceID DESC) as rn
    FROM Phones P
    LEFT JOIN InvoicePhones IP on IP.PhoneId = P.Id 
)
SELECT *
FROM filter 
WHERE rn = 1

<强>输出

enter image description here

答案 1 :(得分:0)

我不确定你想要什么。但你有这个条件:

IP.VoiceId = (select TOP 1 id
              from Voices V
              where V.Id = IP.VoiceId
              order by V.BillingCycle desc
             )

关联条款是V.id = IP.VoiceId。平等比较 - 基本上是 - IP.VoiceId = V.id。他们是一样的。只要Voices中至少有一条匹配记录,那么IP记录就会通过测试。使用您的数据,所有IP条记录都会通过测试。

我不确定你到底想要完成什么。如果您每个手机只需要一行,那么我会考虑EXISTSIN

获得所需结果的最简单方法是:

select p.*
from phones p;

但我怀疑你想要更复杂的逻辑。

答案 2 :(得分:0)

;WITH Phones as
(
    SELECT * FROM (VALUES 
    (1,'602 600 8000'),
    (2,'602 600 8001'),
    (3,'602 600 8002')
    ) AS Vict_t (Id,Number)
), InvoicePhones as
(
    SELECT * FROM (VALUES
    (10, 1, 100, 'Alpha'),
    (11, 1, 101, 'Bravo'),
    (12, 1, 102, 'Charlie'),
    (13, 2, 103, 'Alpha'),
    (14, 2, 104, 'Bravo'),
    (15, 2, 105, 'Charlie'),
    (16, 3, 106, 'Alpha'),
    (17, 3, 107, 'Bravo'),
    (18, 3, 108, 'Charlie')
    ) as ip_t (Id,PhoneId,VoiceId, Name)
), Voices as
(
    SELECT * FROM (VALUES
     (100, '201701'),
     (101, '201702'),
     (102, '201703'),
     (103, '201704'),
     (104, '201705'),
     (105, '201706'),
     (106, '201708'),
     (107, '201709'),
     (108, '201710')
    ) AS Voices_t (Id,BillingCycle)
)
,Expected
AS
(
SELECT P.Id PhoneId, P.Number, IP.Name
FROM Phones P
LEFT JOIN InvoicePhones IP on IP.PhoneId = P.Id and IP.VoiceId =
    (
    SELECT TOP 1 id
    FROM Voices V
    WHERE V.Id = IP.VoiceId
    ORDER BY V.BillingCycle desc
    )
    )
SELECT PhoneId,Number,Name From
(
SELECT *,ROW_NUMBER()OVER(PARTITION BY Phoneid,Number  ORDER BY Phoneid)AS Seq
FROM Expected
)DT
WHERE DT.Seq=3

输出

 PhoneId Number         Name
  ------------------------------
    1    602 600 8000    Charlie
    2    602 600 8001    Charlie
    3    602 600 8002    Charlie