2010-08-16 4 views
2

HI все, У меня возникли некоторые трудности с пониманием обоснования группы путем объединения в SQL Server 2005.SQL группа по п пониманию (простой вопрос/SQL сервер 2005)

У меня есть следующий запрос, который отлично работает и возвращает одну строку для каждого contact.id и 1-й вхождение события

SELECT 
contact.id 
,MIN(eve.date_created) 
FROM _contact contact WITH(nolock) 
INNER JOIN table2 tb2 WITH (nolock) ON contact.id = tb2.id1 
INNER JOIN _event eve WITH (nolock) ON tb2.id2 = eve.id 
INNER JOIN _cashtable cash WITH (nolock) ON cash.contact_id = contact.id 
GROUP BY contact.id 

Однако то, что я ищу, чтобы иметь следующий запрос и еще только вытащить одну строку за contact.id

SELECT 
contact.id 
,MIN(eve.date_created) 
,cash.id2 -- the cash linked to the first event 
,eve.id  -- the first event linked to the contact  
FROM _contact contact with (nolock) 
INNER JOIN _table2 tb2 WITH (nolock) ON contact.id = tb2.id1 
INNER JOIN _event eve WITH (nolock) ON tb2.id2 = eve.id 
INNER JOIN _cashtable cash WITH (nolock) ON cash.contact_id = contact.id 
GROUP BY contact.id 

Я получаю стандартное сообщение об ошибке, говорящее, что мне нужно добавить cash.id2 и eve.id в предложение group by, которое возвращает результаты, которые я не хочу.

Я знаю, что есть потенциальные варианты использования ранга()/секционирования или даже включая

select(MIN(eve.date_created) 

в предложении FROM, но я не уверен, что было бы лучше, чтобы поставить это и я все еще довольно запутанным относительно того, почему SQL требует, чтобы все было включено в группу по заявлению, и поэтому любые советы были бы замечательными :)

Заранее благодарен!

ответ

2

Я думаю, что вам нужно подзапрос соединяющую таблицу событий с агрегацией себя возвращающейся только мин (даты события)

SELECT 
contact.id,min_created,cash.id2 -- the cash linked to the first event 
,eve.id  -- the first event linked to the contact  
FROM _contact contact 
INNER JOIN _table2 tb2 ON contact.id = tb2.id1 
INNER JOIN _event eve ON tb2.id2 = eve.id 
inner join (select id, date_created as min_created from _event group by id) eve_min 
on eve_min.id = eve.id and eve_min.min_created = eve.date_created 
INNER JOIN _cashtable cash ON cash.contact_id = contact.id 
+0

Спасибо за это, я предполагаю, что внутреннее соединение (select id, date_created на самом деле выбирает MIN (date_created)?) При использовании этого он возвращает много строк на contact_id (около 50) вместо одного, есть ли какие-либо причина для этого? (в случае, если он помогает использовать выделение отдельных половинок числа строк, возвращаемых примерно до 25 на контакт) – Dibstar

+0

да, вы правы, я должен был применить функцию min() к date_created. Если это возвращает больше чем одна строка, тогда он получает оставшиеся строки из события, если для одного и того же min_created или наличных денег есть более одного, если на каждый идентификатор есть несколько строк. – Beth

0

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

Другой альтернативой является добавление предложений к объединениям, чтобы ограничить его первым или MIN ID, тогда вам не понадобится группировка.

+0

Проблема с этим состоит в том, что (извиняюсь за не будучи более специфичным), наличные деньги .id2 - это текстовая ссылка для фактического значения денежных средств, и поэтому применение MIN() к ней возвращает ошибку – Dibstar

+0

Является ли идентификатор еще чисто числовым значением? Если это так, преобразование в int не добавит столько накладных расходов в схему вещей, а затем вы можете выбрать значение MIN. Не самая идеальная ситуация, но она все равно будет работать.Выполнение преобразования за пределами соединения, хотя и для функций агрегации, было бы намного дешевле, чем конверсия в рамках соединения. Итак, сделайте преобразование в идентификаторе внутри выделения. MIN (CONVERT (INT, cash.id2)) –

+0

Нет, все поля ID представляют собой nvarchar (s), содержащие смесь цифр и букв, и поэтому, по-видимому, невозможно эффективно преобразовать в целые числа для ранжирования или функции MIN/MAX? – Dibstar

0

Вам не нужно добавлять их в предложение group-by, но вам нужно как-то их заполнить. Точка предложения group-by заключается в том, что вы хотите группировать статистику. То есть вы хотите все для того же идентификатора контакта, а не только для первой записи.

Я считаю, что если вы делаете что-то вроде

SELECT Contact.Id, 
    MIN(eve.date_created), 
    MAX(eve.date_created), //this will get you the range of events 
    SUM(cash.id2), //total cash for all events 
    MIN(eve.Id), //First event id 
    MAX(eve.Id) //Latest event id 
FROM _contact Contact //Etc. etc. 

ваш запрос будет работать для группировки. Что кажется, что вы хотите, однако, больше похож:

[Select your columns] 
FROM _contact Contact 
INNER JOIN _Table2 tb2 on contact.id = tb2.id1 
    and tb2.id1 = (Select MIN(id2) from tb2 where tb2.id1 = contact.id) 
INNER JOIN _event eve on tb2.Id2 = eve.id 
INNER JOIN _cashtable cahs on cash.contact_id = contact.id 
    and cash.id = (select MIN(id) from cash where cash.contact_id = contact.id) 

YMMV, и я ваша структура таблицы будет частично диктовать, как быстро, что работает (то есть, вы можете захотеть взглянуть на некоторые оптимизации). Кроме того, я сделал это полностью из памяти, поэтому вам может понадобиться играть с этими INNER JOIN s, чтобы заставить их работать. Дело в том, что вы не пытаетесь схватить группу, пытаясь захватить первый за каждый contact.id.

+0

Благодарим за это, к сожалению, поле cash.id2 является текстовым полем, поэтому применение ограничения MIN() вызывает ошибку. Для этой таблицы мне нужно будет вытащить cash.id2, который напрямую связан с значением MIN (eve.date_created) - есть ли способ просто получить азасованное значение, не добавляя его в предложение группы? Спасибо :) – Dibstar