Что плохого в этом соединении таблицы с самим собой? - PullRequest
4 голосов
/ 13 декабря 2010

У меня есть таблица с именем TempAllAddresses со следующими столбцами - ID, Address, State. Я хочу заполнить новую таблицу Address, State и Count. Count должно отображать, сколько записей в таблице TempAllAddresses имеется адрес, подобный этому адресу, за которым следует подстановочный знак. Если это не имеет смысла, вот пример для иллюстрации - Допустим, у меня есть такая запись:

ID      Address      State
12345   13 Phoenix   NY

Я хочу вставить новую запись в новую таблицу с именем AddressCount, в которой 13 Фениксов для Address, NY для State и количество записей в таблице, в которых NY равно штат и адрес как "13 Феникс%" для Count.

Я хочу сделать это внутренним соединением TempAllAddresses. Это то, что я пытался, но, похоже, не достиг того, что я искал:

SELECT t1.Address, t1.State, COUNT(t2.address) As NumEntities
FROM TempAllAddresses t1
INNER JOIN TempAllAddresses t2
 ON t1.state = t2.state
 AND T2.Address LIKE t1.address + '%'
GROUP BY t1.State, t1.Address

Граф точно выключен. Это должно быть эквивалентно выполнению "SELECT COUNT(*) FROM TempAllAddresses WHERE State=thisRecordsState and Address LIKE thisRecordsAddress + '%'". Как я могу сделать это? Что я делаю не так?

Edit:

Счет, кажется, выключен следующим образом - Если у меня есть запись, как я упоминал выше, а затем у меня есть две другие записи, которые также имеют штат Нью-Йорк, а затем имеют адреса «13 Phoenix Road» и «13 Phoenix Rd», то я хочу попасть в свой финал Таблица записи, как это:

13 Phoenix    NY    3

Вместо этого я, кажется, получаю:

13 Phoenix    NY    9

Я не совсем уверен, что здесь происходит ... какой-то декартово произведение? Перестановки ...? Кто-нибудь может объяснить это?

Редактировать 2: Дальнейшее редактирование, так как мне кажется, что меня неправильно поняли (и мне действительно нужно решение :() ... Вот запрос с коррелированным подвыбором, который выполняет то, что я ищу. Я хотел бы сделать то же самое с внутренним объединение таблицы на себя, а не на подвыбор.

SELECT Address, State, 
    (SELECT Count(*)
    FROM TempAllAddresses innerQry 
    WHERE innerQry.address LIKE outerQry.address + '%' 
        AND innerQry.state = outerQry.state) As NumEntities
FROM TempAllAddresses outerQry

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

Ответы [ 7 ]

1 голос
/ 01 января 2011

Вот два решения, одно из которых использует CROSS APPLY, а другое - INNER JOIN, как вы и хотели изначально. Надеюсь, это поможет. :)

DECLARE @TempAllAddresses TABLE
(
    ID INT PRIMARY KEY IDENTITY(1, 1) NOT NULL
    , [Address] VARCHAR(250) NOT NULL
    , [State] CHAR(2) NOT NULL
)

INSERT INTO @TempAllAddresses
VALUES ('13 Phoenix', 'NY')
        , ('13 Phoenix St', 'NY')
        , ('13 Phoenix Street', 'NY')
        , ('1845 Test', 'TN')
        , ('1337 Street', 'WA')
        , ('1845 T', 'TN')

SELECT
    TempAddresses.ID
    , TempAddresses.[Address]
    , TempAddresses.[State]
    , TempAddressesCounted.AddressCount
FROM @TempAllAddresses TempAddresses
CROSS APPLY
(
    SELECT
        COUNT(*) AS AddressCount
    FROM @TempAllAddresses TempAddressesApply
    WHERE TempAddressesApply.[Address] LIKE (TempAddresses.[Address] + '%')
        AND TempAddressesApply.[State] = TempAddresses.[State]
) TempAddressesCounted

SELECT
    TempAddresses.ID
    , TempAddresses.[Address]
    , TempAddresses.[State]
    , COUNT(*) AS AddressCount
FROM @TempAllAddresses TempAddresses
INNER JOIN @TempAllAddresses TempAddressesJoin
    ON TempAddressesJoin.[Address] LIKE (TempAddresses.[Address] + '%')
            AND TempAddressesJoin.[State] = TempAddresses.[State]
GROUP BY TempAddresses.ID
    , TempAddresses.[Address]
    , TempAddresses.[State]
0 голосов
/ 31 декабря 2010

Вы пробовали аналитические функции - они часто являются самым простым решением. Я не знаком с вашей структурой таблицы, но она должна выглядеть примерно так:

SELECT t1.Address, t1.State, 
COUNT(t2.address) OVER (PARTITION BY t2.state) As NumEntities
FROM TempAllAddresses t1
INNER JOIN TempAllAddresses t2
ON t1.state = t2.state
AND T2.Address LIKE t1.address + '%'
GROUP BY t1.State, t1.Address

Вы можете даже добавить ORDER BY в предложение OVER. См. Часто задаваемые вопросы по Oracle для некоторых объяснений.

0 голосов
/ 14 декабря 2010

Nested GroupBy:

  • Подзапрос найдет самый короткий адрес для каждого отдельного адреса.
  • Это не учитывает чувствительность к регистру.
  • Затем подсчитываются все версии этих адресов.

SQL:

SELECT Address, State, count(1) As NumEntities
FROM ( 
    SELECT min(t1.Address) as Address, t1.State
    FROM TempAllAddresses t1
    INNER JOIN TempAllAddresses t2
     ON t1.state = t2.state
     AND T2.Address LIKE t1.address + '%'
    GROUP BY t1.State, t2.Address
) GROUP By State, Address
0 голосов
/ 13 декабря 2010

При наличии нескольких строк с одинаковым адресом происходит двойной подсчет.

Попытка:

SELECT t1.Address, t1.State, COUNT(t2.address) As NumEntities
FROM (select distinct Address, State from TempAllAddresses) t1
INNER JOIN TempAllAddresses t2
 ON t1.state = t2.state
 AND T2.Address LIKE t1.address + '%'
GROUP BY t1.State, t1.Address
0 голосов
/ 13 декабря 2010

QUERY A:

SELECT t1.Address, t1.State, COUNT(t2.address) As NumEntities
FROM TempAllAddresses t1
INNER JOIN TempAllAddresses t2
 ON t1.state = t2.state
 AND T2.Address LIKE t1.address + '%'
GROUP BY t1.State, t1.Address

не эквивалентно

QUERY B:

SELECT Address, State, 
    (SELECT Count(*)
    FROM TempAllAddresses innerQry 
    WHERE innerQry.address LIKE outerQry.address + '%' 
        AND innerQry.state = outerQry.state) As NumEntities
FROM TempAllAddresses outerQry

, поскольку B создает 1 строку для каждой строки в исходной таблице (TempAllAddresses), тогда как A сгруппирует строки в исходной таблице, которые имеют одинаковое состояние и адрес.Чтобы решить эту проблему, вместо этого GROUP BY t1.ID, t1.State, t1.Address.

0 голосов
/ 13 декабря 2010

РЕДАКТИРОВАТЬ: [отрывать старые вещи]

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

SELECT t1.Address, t1.State, COUNT(distinct t2.id) As NumEntities
FROM TempAllAddresses t1
INNER JOIN TempAllAddresses t2
 ON t1.state = t2.state
 AND T2.Address LIKE t1.address + '%'
GROUP BY t1.State, t1.Address
0 голосов
/ 13 декабря 2010

Попробуйте вместо этого:

SELECT Orig_Address, State, COUNT(Similar_Address)
From
(
  SELECT t1.Address Orig_Address, 
         t1.State   State, 
         t2.address Similar_Address
    FROM TempAllAddresses t1
   INNER JOIN TempAllAddresses t2
      ON t1.state = t2.state
     AND T2.Address LIKE t1.address + '%'
     AND t1.address <> t2.address
)
GROUP BY State, Orig_Address

РЕДАКТИРОВАТЬ: забыл указать разницу между t1.address и t2.address, как сказал @Spiny Norman, поскольку вы, вероятно, не хотите сравнивать адрес с самим собой.

НТН

...