SQL JOIN + GROUPBY выбрать данные из строки с MAX (Дата) - PullRequest
2 голосов
/ 23 декабря 2011

У меня проблемы с поиском решения этого SQL-запроса.

Схема

Редактировать : Добавление таблицы элементов

Таблица элементов

  • PK ItemID
  • много других столбцов

Таблица связывания

  • FK ItemID уникальный идентификатор
  • FK TransactionID уникальный идентификатор

Таблица транзакций

  • PK ID уникальный идентификатор
  • EntryDateTime DateTime
  • (несколько других строк типа int, varchar ...)

Редактировать : Мне кажется, я не прояснил отношения. Каждый ПУНКТ (таблица не показана) может иметь несколько транзакций. Несколько элементов могут совместно использовать одну и ту же транзакцию (отсюда и таблица ссылок).

Пожалуйста, смотрите в нижней части для моего текущего запроса. Я оставил это пораженным, чтобы показать ход вопроса.

Я хочу сделать что-то вроде этого запроса. Хитрость заключается в том, что я хочу, чтобы столбцы t.varchar и t.int имели значения в строке MAX (t.EntryDateTime). Я даже не знаю, является ли group by правильным способом выполнения этого запроса.

SELECT lt.ItemID, MAX(t.EntryDateTime), t.varchar, t.int 
FROM LinkingTable lt
LEFT JOIN Transactions t ON lt.TransactionID = t.ID
GROUP BY lt.ItemID 

Эта таблица будет объединена в этом запросе SQL, поэтому, пожалуйста, попробуйте дать мне наиболее эффективное решение. Предположим, что Table1 будет содержать миллионы записей.

SELECT 
(many columns)
FROM Table1
LEFT JOIN Table2 ON Table1.Table2ID = Table2.ID
LEFT JOIN Table3 ON ....
LEFT JOIN Table4 ON (Table2.ID = Table4.Table2ID and Table4.LocaleID = 127 and Table4.Type = 0)
LEFT JOIN **the query above** AS vTable1 ON  vTable1.ItemID = Table1.ID
WHERE Table1.CheckID IN (SELECT ID FROM Checks WHERE ....)

Редактировать : У меня есть запрос, который работает , но я не уверен, что он наиболее эффективен. LinkingTable имеет ~ 200 тыс. Записей, и его запуск занимает 6 секунд.

SELECT DISTINCT lt.ItemID, t.EntryDateTime,  t.varchar, t.int
FROM LinkingTable lt 
     LEFT JOIN Transactions t ON t.id = (SELECT Top 1 t2.id FROM LinkingTable lt2
LEFT JOIN Transactions t2 on lt2.TransactionID = t2.ID
where lt2.ItemID = lt.ItemID ORDER BY t2.PrintTime DESC)

Ответы [ 4 ]

1 голос
/ 23 декабря 2011

Даже при наличии более миллиона записей у вас будут некоторые проблемы с производительностью, но я бы гарантировал и проиндексировал таблицу транзакций на основе (ItemID, Primary Key).Причина Первичный ключ, а не дата - если его автоматически увеличивают, а его дата / время помечают в момент совершения транзакции, они будут по сути едиными.Последняя запись в файле всегда будет иметь самую последнюю дату.При этом столбец идентификатора должен быть быстрее с индексом, чем дата / время.Это также избавляет от необходимости просматривать ОБА элементы с самой последней датой и идентификатор транзакции, связанный с этой датой.Вот как я бы ПЕРВЫЙ попытался запрос.

select 
      I.*,
      T2.*
   from
      Item I
         JOIN 
            ( select T.ItemID, MAX( T.PrimaryKey ) as LastEntryPerItem 
                 from Transactions T
                 group by T.ItemID ) MaxPerItem
            ON I.ItemID = T.ItemID

            JOIN Transactions T2
               on MaxPerItem.LastEntryPerItem = T2.PrimaryKey
   order by
      whatever
1 голос
/ 23 декабря 2011

Попробуйте это,

SELECT i.*, outerT.EntryDateTime, outerT.varchar, outerT.int
FROM Item i
     LEFT JOIN
     (SELECT ItemId AS outerItemId, EntryDateTime, varchar, int
      FROM (SELECT ROW_NUMBER() OVER (PARTITION BY lt.ItemId ORDER BY t.EntryDateTime) AS RowNumber, lt.ItemId, t.EntryDateTime, t.varchar, t.int
            FROM Tranaction t INNER JOIN LinkingTable lt ON lt.TransactionId = t.ID) innerT
      WHERE RowNumber = 1) outerT ON outerT.outerItemId = Item.ID

Надеюсь, что это решит вашу проблему

0 голосов
/ 23 декабря 2011

Почему бы вам не создать представление, содержащее все ваши "много столбцов", а затем выполнить запрос к этому представлению?

0 голосов
/ 23 декабря 2011
select lt.ItemId, t.entrydatetime, t.varchar, t.int
from LinkingTable lt
left join transactions t 
     on lt.transactionId = t.id
        and t.entryDateTime = (select max(t.EntryDateTime)
                               from transactions t2
                               where t2.id = t.id)

У меня был похожий вопрос раньше ( SQL Join, чтобы получить значение принадлежат самой последней дате ). Есть еще одно решение от JNK, включающее два соединения, которые могут быть быстрее. Я разместил ниже. Вам нужно будет проверить, какие из них работают лучше.

select lt.ItemId, t.entrydatetime, t.varchar, t.int
from LinkingTable lt
inner join transactions t 
   on lt.ItemId= t.ItemId
Inner join (SELECT ItemId, MAX(entrydatetime) entrydatetime
            FROM transactions t2
            GROUP BY ItemId) SubQ
ON SubQ.ItemId= t.ItemId
AND SubQ.entrydatetime= t.entrydatetime
...