Вопрос SQL-запроса - Как выбрать группы строк, используя общности - PullRequest
3 голосов
/ 21 марта 2011

Я работаю с данными переписи и хочу предоставить возможность поиска записей, предоставив список имен. Идея состоит в том, что если вы знаете имя или 2 или 3 члена семьи, вы сможете исключить все адреса, у которых нет этих имен. Рассмотрим этот пример набора данных (адрес, фамилия, имя):


«Жители дома 2 в Джейнмаунт-Лоуэр (пробка № 4, городская часть (пробка), пробка)», «Азартная игра», «Юлия»
«Жители дома 2 в районе Джейнмаунт Нижний (Корк № 4, Урбан (часть), Корк)», «Азартная игра», «Ричард»
«Жители дома 2 в районе Джейнмаунт Нижний (Корк № 4, Урбан (часть), Корк)», «Азартная игра», «Ханна»
«Жители дома 2 в районе Джейнмаунт Нижний (пробка № 4, городская часть (пробка)», «Азартная игра», «Елена»


Поиск Джулии, Ханны и Хелен должен быть в состоянии вернуть все 4 строки, поскольку они имеют общий адрес. Звучит достаточно просто, но у меня проблемы с этим. Курсоры отсутствуют из-за размера набора данных. Есть идеи?

(Излишне говорить, что я несколько упростил это, поскольку пока игнорирую часть поиска по фамилии)

Ответы [ 9 ]

1 голос
/ 21 марта 2011

Этот запрос:

       select streetaddress, count(*) as occupantcount
       from census
       where firstname in ("Julia", "Hannah", "Helen")
       group by streetaddress
       order by occupantcount desc

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

1 голос
/ 21 марта 2011

Это проблема реляционного деления n.

SELECT Address, FamilyName, Forename
FROM   YourTable
WHERE  Address IN (SELECT Address
                   FROM   YourTable
                   WHERE  Forename IN ( 'Julia', 'Hannah', 'Helen' )
                   GROUP  BY Address
                   HAVING COUNT(DISTINCT Forename) = 3)  

Или

WITH Names(name)
     AS (SELECT 'Julia'
         UNION ALL
         SELECT 'Hannah'
         UNION ALL
         SELECT 'Helen')
SELECT Address,
       FamilyName,
       Forename
FROM   YourTable y1
WHERE  NOT EXISTS (SELECT *
                   FROM   Names n
                   WHERE  NOT EXISTS(SELECT *
                                     FROM   YourTable y2
                                     WHERE  y1.Address = y2.Address
                                            AND y2.Forename = n.Name))  
1 голос
/ 21 марта 2011

Вы можете попробовать это:

SELECT A.*
FROM YourTable A
JOIN (  SELECT Address, COUNT(*) Quant
        FROM YourTable
        WHERE Forename IN ('Julia','Hannah','Helen')
        GROUP BY Address
        HAVING COUNT(DISTINCT Forename) > 2) B
ON A.Address = B.Address
0 голосов
/ 21 марта 2011
DECLARE @namecount int;
DECLARE @forenames TABLE (name varchar(50));
INSERT INTO @forenames
VALUES ('...'),
       ('...'),
       ('...');
SELECT @namecount = COUNT(*) FROM @forenames;

/* list all people by addresses that are shared by people
   whose forenames are included in @forenames */
SELECT cd.*
FROM CensusData cd
  INNER JOIN (
    SELECT d.Address
    FROM CensusData d
      INNER JOIN @forenames f ON d.Forename = f.Name
    GROUP BY d.Address
    HAVING COUNT(DISTINCT d.Forename) >= @namecount
  ) filter ON cd.Address = filter.Address

/* same for family names */
SELECT cd.*
FROM CensusData cd
  INNER JOIN (
    SELECT d.[Family Name]
    FROM CensusData d
      INNER JOIN @forenames f ON d.Forename = f.Name
    GROUP BY d.Address
    HAVING COUNT(DISTINCT d.Forename) >= @namecount
  ) filter ON cd.[Family Name]= filter.[Family Name]

/* and so on fro other criteria */

При необходимости вы также можете комбинировать критерии.

0 голосов
/ 21 марта 2011

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

declare @people table (
    address varchar(255),
    familyName varchar(255),
    forename varchar(255)
)

insert into @people
values ('Residents of a house 2 in Janemount Lower (Cork No. 4 Urban (part of), Cork)', 'Gamble', 'Julia')
insert into @people
values ('Residents of a house 2 in Janemount Lower (Cork No. 4 Urban (part of), Cork)', 'Gamble', 'Richard')
insert into @people
values ('Residents of a house 2 in Janemount Lower (Cork No. 4 Urban (part of), Cork)', 'Gamble', 'Hannah')
insert into @people
values ('Residents of a house 2 in Janemount Lower (Cork No. 4 Urban (part of), Cork)', 'Gamble', 'Helen')
insert into @people
values ('Residents of a house 2 somewhere else (Cork No. 4 Urban (part of), Cork)', 'Cooper', 'Helen')

select people.*
from @people as people
where people.address in (
    select address
    from @people
    where forename in ('Julia', 'Hannah', 'Helen')
    group by address
    having count(forename) >= 3 -- This must be equal to the number of names searched for
)

Одна проблема, связанная с этим решением, заключается в том, что, если по одному адресу проживают три Ханны, запрос вернет этих людей, даже если Джулия и Елена там не живут.

0 голосов
/ 21 марта 2011

Если вы указали имя и адрес, это должно быть просто и быстро:

SELECT a.Address as CommonAddress
FROM (SELECT Address FROM Names WHERE Forename = 'Julia') a
INNER JOIN (SELECT Address FROM Names WHERE Forename = 'Richard') b ON a.Address=b.Address
INNER JOIN (SELECT Address FROM Names WHERE Forename = 'Helen') c on b.Address=c.Address
0 голосов
/ 21 марта 2011
SELECT t.address
     , t.familyname
     , t.forename 
  FROM yourTable t
  WHERE t.address IN 
    -- search subquery
    ( SELECT s1.address 
        FROM yourTable s1
          JOIN yourTable s2
            ON s2.address = s1.address
          JOIN yourTable s3
            ON s3.address = s1.address
        WHERE s1.forename = "Julia"
          AND s2.forename = "Hannah"
          AND s3.forename = "Helen"
    )
  ORDER BY t.address
         , t.familyname
         , t.forename 
;

2-е решение:

SELECT t.address
     , t.familyname
     , t.forename 
  FROM yourTable t
  WHERE EXISTS 
    -- search subquery
    ( SELECT * 
        FROM yourTable s1
          JOIN yourTable s2
            ON s2.address = s1.address
          JOIN yourTable s3
            ON s3.address = s1.address
        WHERE s1.forename = "Julia"
          AND s2.forename = "Hannah"
          AND s3.forename = "Helen"
          AND s1.address = t.address
    )
  ORDER BY t.address
         , t.familyname
         , t.forename 
;

3-е решение:

SELECT t.address
     , t.familyname
     , t.forename
  FROM yourTable t
  WHERE  -- search subqueries
    EXISTS
      ( SELECT * 
          FROM yourTable s1
            WHERE s1.forename= "Julia"
              AND s1.address = t.address
      )
    AND EXISTS
      ( SELECT * 
          FROM yourTable s2
            WHERE s2.forename = "Hannah"
              AND s2.address = t.address
      )
    AND EXISTS
      ( SELECT * 
          FROM yourTable s3
            WHERE s3.forename = "Helen"
              AND s3.address = t.address
      )
  ORDER BY t.address
         , t.familyname
         , t.forename 
;
0 голосов
/ 21 марта 2011

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

Select
    T1.*
From
    TableName T1
Inner Join
    TableName T2
On
    T1.Address = T2.Address
Where
    T1.ForeName = 'Julia'
0 голосов
/ 21 марта 2011
select *
from dataset
where address = (
    select address
    from dataset
    where famly_name = 'Hannah' and forename = 'Gamble'
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...