Почему этот множественный запрос на соединение с SQL Server не выполняется - PullRequest
0 голосов
/ 10 января 2019

У меня есть таблица в этом формате:

PID   TIV_2011  TIV_2012     LAT         LON
123     1000      1200     20.123489   80.341245
456     1500      3000     21.341287   80.341245
789     2000      1500     21.341287   80.341245
321     1000       750     21.123641   80.238716
567     1500      2300     22.123641   80.238716

Вопрос. Напишите запрос для вывода суммы всех общих значений инвестиций в 2012 году (TIV_2012) в масштабе 2 десятичных знака для всех держателей полисов, которые соответствуют следующим критериям:

  1. имеют то же значение TIV_2011, что и один или несколько других держателей полисов.

  2. Не расположены в том же городе, что и другой страхователь (т. Е. Пара атрибутов широта, долгота) должна быть уникальной).

Мой запрос:

select cast(sum(i1.tiv_2012) as decimal(12,2))
from insurance i1 join insurance i2 on i1.tiv_2011 = i2.tiv_2011
where i1.pid != i2.pid 
and i1.lat != i2.lat 
and i1.lon != i2.lon

Ответ - 7250, что составляет 1200 + 3000 + 750 + 2300.

Но фактический ответ должен быть 4250, что составляет 1200 + 750 + 2300

На этот вопрос уже был дан ответ, и запрос, который отлично работает:

select cast(sum(i1.tiv_2012) as decimal(12,2)) from insurance i1 
join (select TIV_2011 from insurance group by TIV_2011 having count(*) > 1) i2 on i1.tiv_2011 = i2.TIV_2011
join (select lat,LON from insurance group by LAT,LON having COUNT(*) = 1) i3 on i1.LAT = i3.LAT and i1.LON = i3.LON

Но может кто-нибудь сообщить мне, где или почему мои соединения не работают?

Ответы [ 4 ]

0 голосов
/ 10 января 2019

Предпочитают писать более простой SQL, который отражает требования. Если вы хотите сделать это с помощью объединений, это может быстро выйти из-под контроля, поскольку объединения будут пересекаться друг с другом и увеличивать количество строк. Кроме того, два пронумерованных предложения требуют различных условий для выражения, а второе выполнимо только с LEFT JOIN, который, как вы надеетесь, потерпит неудачу.

Я бы предпочел использовать два EXISTS чека:

declare @t table (PID int, TIV_2011 int, TIV_2012 int, Lat decimal(8,6),Lon decimal(9,6))
insert into @t(PID,TIV_2011,TIV_2012,LAT,LON) values
(123,1000,1200,20.123489,80.341245),
(456,1500,3000,21.341287,80.341245),
(789,2000,1500,21.341287,80.341245),
(321,1000, 750,21.123641,80.238716),
(567,1500,2300,22.123641,80.238716)

select
    CONVERT(decimal(12,2),SUM(TIV_2012))
from
    @t t_keep
where
    exists (select * from @t t_other2011
       where t_keep.PID != t_other2011.PID
       and t_keep.TIV_2011 = t_other2011.TIV_2011
) and
    not exists (select * from @t t_city
       where t_keep.PID != t_city.PID and
       t_keep.Lat = t_city.Lat and
       t_keep.Lon = t_city.Lon)

Выберите строки из @t (t_keep), где (сначала EXISTS) есть еще одна строка в таблице для другого держателя страхового полиса, где мы разделяем то же значение TIV_2011. Но также (and) где (секунда EXISTS) там не является строкой в ​​таблице для другого держателя полиса, где у нас одни и те же значения Lat и Lon.

Это дает значение 4250.

0 голосов
/ 10 января 2019

У вас есть два независимых условия, но вы пытаетесь использовать их вместе. Разделите их, например, с помощью подзапроса, и вы получите ожидаемый результат.

DECLARE @Test TABLE (
    PID         int,
    TIV_2011    int,
    TIV_2012    int,
    LAT         DECIMAL(8,6),        
    LON         DECIMAL(8,6)
) 
INSERT @Test(PID,   TIV_2011,  TIV_2012,     LAT,         LON)
VALUES
(123, 1000, 1200, 20.123489, 80.341245),
(456, 1500, 3000, 21.341287, 80.341245),
(789, 2000, 1500, 21.341287, 80.341245),
(321, 1000,  750, 21.123641, 80.238716),
(567, 1500, 2300, 22.123641, 80.238716)

select cast(sum(i1.tiv_2012) as decimal(12,2))
from @Test i1 
    join @Test i2 on i1.tiv_2011 = i2.tiv_2011
        AND i1.pid != i2.pid 
where 
    NOT EXISTS (
        SELECT 1
        FROM @Test
        WHERE LAT = i1.lat 
            and LON = i1.lon
            AND PID != i1.pid
    )
0 голосов
/ 10 января 2019

Это не та задача, к которой я бы присоединился вообще.

select sum(tiv_2012)
from insurance i
where exists
(
  select * 
  from mytable other 
  where other.pid <> i.pid
  and other.tiv_2011 = i.tiv_2011
)
and not exists
(
  select * 
  from mytable other 
  where other.pid <> i.pid
  and other.lat = i.lat
  and other.lon = i.lon
);

Я знаю, что это не отвечает на ваш вопрос, что именно не так с вашими объединениями. На мой взгляд, это подход, позволяющий даже использовать объединения здесь, когда вам нужно только посмотреть другие строки в таблице. Для поиска записей у нас есть EXISTS и IN, а критерии идут к предложению WHERE, как и должно быть.

0 голосов
/ 10 января 2019

ваша эта строка отличается и не имеет смысла.

i1.pid != i2.pid 

Этого не должно быть там.

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