Ограничение результатов при присоединении к запросу - PullRequest
2 голосов
/ 17 февраля 2010

Скажите, у меня есть следующие таблицы:

|RefNumber| Charge| IssueDate|
------------------------------
|    00001|   40.0|2009-01-01|
|    00002|   40.0|2009-06-21|

|ID|RefNumber|Forename|   Surname|
---------------------------------
  1|    00001|     Joe|     Blogs|  
  2|    00001|   David|     Jones|
  3|    00002|    John|     Smith|
  4|    00002|    Paul|     Walsh|

Я хотел бы выбрать refnumber, поручить и выдать из первой таблицы, затем присоединить refnumber ко второй таблице, чтобы получить имя и фамилию, но получить только строку с самым высоким идентификатором.

Таким образом, результаты будут выглядеть так:


|RefNumber| Charge| IssueDate|ID|Forename|   Surname|
-----------------------------------------------------
|    00001|   40.0|2009-01-01| 2|   David|     Jones|
|    00002|   40.0|2009-06-21| 4|    Paul|     Walsh|

Я не уверен, кто ограничит результаты в соединении, чтобы вернуть только запись с самым высоким ID из второй таблицы.

Ответы [ 4 ]

1 голос
/ 17 февраля 2010

Самый гибкий способ написать это, не требующий коррелированного подзапроса, - это использовать ROW_NUMBER (только для SQL Server 2005+):

;WITH Names_CTE AS
(
    SELECT
        ID, RefNumber, Forename, Surname,
        ROW_NUMBER() OVER (PARTITION BY RefNumber ORDER BY ID) AS RowNum
    FROM Names
)
SELECT o.RefNumber, o.Charge, o.IssueDate, n.Forename, n.Surname
FROM Orders o
[INNER|LEFT] JOIN Names_CTE n
    ON n.RefNumber = o.RefNumber
WHERE n.RowNum = 1

Обратите внимание, что ROW_NUMBER не всегда наиболее эффективен, если вместо него можно использовать MIN/MAX, просто проще всего писать.

Если вы используете SQL 2000 или он недостаточно эффективен, вы можете попробовать запрос MIN или MAX:

SELECT o.RefNumber, o.Charge, o.IssueDate, n.Forename, n.Surname
FROM Orders o
[INNER|LEFT] JOIN
(
    SELECT RefNumber, MIN(ID) AS MinID
    FROM Names
    GROUP BY RefNumber
) m
    ON m.RefNumber = o.RefNumber
[INNER|LEFT] JOIN Names n
    ON n.ID = m.MinID

Иногда это на самом деле быстрее, это во многом зависит от используемой стратегии индексации.

(Правка - получаются строки с наименьшим ID, который в большинстве случаев будет быстрее, чем наибольший ID. Если вам нужен самый высокий, измените первый запрос на ORDER BY ID DESC и второй запрос для использования MAX вместо MIN).

1 голос
/ 17 февраля 2010

Я бы, вероятно, присоединился к подзапросу, который возвращает только запись из второй таблицы с наибольшим идентификатором.

select a.RefNumber, a.Charge, a.IssueDate, b.ID, b.Forename, b.Surname
from References a inner join
    (select ID, RefNumber, ForeName, Surname from Names n1
        where n1.ID = (select top 1 n2.ID from Names n2 where n1.RefNumber = n2.RefNumber) ) b
    on a.RefNumber = b.RefNumber
0 голосов
/ 17 февраля 2010
select nt.RefNumber, ct.Charge, ct.IssueDate, nt.ID, nt.Forename, nt.Surname
from NameTable nt
join ChargeTable ct on (ct.RefNumber = nt.RefNumber)
where nt.ID = (select MAX(nt2.id) 
               from NameTable nt2 
               where nt2.RefNumber = nt.RefNumber)
order by nt.ID
0 голосов
/ 17 февраля 2010

На самом деле ваш подзапрос должен будет выбрать самый высокий идентификатор для КАЖДОГО номера refnumber, так что это будет выглядеть примерно так:

select 
        a.RefNumber, a.Charge, a.IssueDate, b.BiggestID, b.Forename, b.Surname
from References a 
inner join
    (select
           RefNumber,
           max(ID) as BiggestID
     from Names
     group by
           RefNumber) b
    on a.RefNumber = b.RefNumber

Надеюсь, это поможет. -Т

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...