2013-08-23 10 views
1

У меня проблема, с которой я работаю с Oracle SQL, которая выглядит примерно так.Oracle SQL - Сравнение строк

ТАБЛИЦА

PurchaseID CustID  Location 
----1------------1-----------A 
----2------------1-----------A  
----3------------2-----------A 
----4------------2-----------B 
----5------------2-----------A 
----6------------3-----------B 
----7------------3-----------B 

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

ВЫВОД

PurchaseID CustID  Location 
----3------------2-----------A 
----4------------2-----------B 
----5------------2-----------A 

Любые идеи о том, как это сделать? Я не мог придумать, как это сделать, и большинство моих идей похоже, что они будут довольно неуклюжими. База данных, которую я использую, имеет записи 1MM +, поэтому я не хочу, чтобы она выполнялась слишком медленно.

Любая помощь будет оценена по достоинству. Благодаря!

+0

Сколько разных мест, сколько разных клиентов? –

+0

Вопрос - это упрощенная версия того, что я действительно делаю на работе, но в реальной базе данных существует 5 различных значений для переменной, которую я вызываю здесь, здесь (также некоторые нули), и существует около 500 000 разных «клиентов» «. – user1895076

+0

Тогда было бы лучше всего в плане производительности построить все пять наборов для разных местоположений и пересечь их. –

ответ

8
SELECT * 
FROM YourTable T 
WHERE CustId IN (SELECT CustId 
       FROM YourTable 
       GROUP BY CustId 
       HAVING MIN(Location) <> MAX(Location)) 
+0

Это было быстро! Благодаря! Что такое Min (Location) <> MAX (Location), что заставляет его работать? – user1895076

+0

@ user1895076 Для обеспечения того, что у него есть как минимум 2 разных местоположения. Вы также можете использовать 'HAVING COUNT (DISTINCT Location)> 1' – Lamak

+0

Ah, gotcha. Min будет минимальное количество мест CustID? Кроме того, я собирался заняться этим следующим, возможно, вы можете помочь. У меня есть четвертая колонка с датой покупки. Следующим шагом я хотел уменьшить таблицу OUTPUT выше, вплоть до тех случаев, когда в течение двух лет были сделаны покупки в разных местах. Он должен возвращать все случаи, когда один клиент совершил по меньшей мере две покупки в разных местах в течение двух лет друг от друга. – user1895076

0

Вот один подход, используя подзапрос

SELECT T1.PurchaseID 
     ,T1.CustID 
     ,T1.Location 
FROM YourTable T1 
INNER JOIN 
     (SELECT T2.CustID 
       ,COUNT (DISTINCT T2.Location) 
     FROM YourTable T1 
     GROUP BY 
       T2.CustID 
     HAVING COUNT (DISTINCT T2.Location)>1 
     ) SQ 
ON  SQ.CustID = T1.CustID 
7

Вы должны быть в состоянии использовать что-то похожее на следующее:

select purchaseid, custid, location 
from yourtable 
where custid in (select custid 
        from yourtable 
        group by custid 
        having count(distinct location) >1); 

См SQL Fiddle with Demo.

подзапрос в предложении WHERE возвращает все custids, которые имеют общее число различных мест, которые больше 1.

5

На английском языке:

Выберите строку, если другая строка существует с тот же клиент и другое место.

В SQL:

SELECT * 
FROM atable t 
WHERE EXISTS (
    SELECT * 
    FROM atable 
    WHERE CustID = t.CustID 
    AND Location <> t.Location 
); 
+0

+1 Мне нравится этот лучше, чем у меня – Lamak

0

Это требуется только один полный просмотр таблицы.

create table test (PurchaseID number, CustID number, Location varchar2(1)); 
insert into test values (1,1,'A'); 
insert into test values (2,1,'A'); 
insert into test values (3,2,'A'); 
insert into test values (4,2,'B'); 
insert into test values (5,2,'A'); 
insert into test values (6,3,'B'); 
insert into test values (7,3,'A'); 

with repeatCustDiffLocations as (
    select PurchaseID, custid, location, dense_rank() over (partition by custid order by location) r 
    from test) 
select b.* 
from repeatCustDiffLocations a, repeatCustDiffLocations b 
where a.r > 1 
and a.custid = b.custid; 
0

Это делает больше смысла для меня, как я пытался вернуть строки с одинаковыми значениями по всей таблице, в частности, для двух столбцов, как показано in this stackoverflow answer here.

ответ на вашу проблему в этом формате:

SELECT DISTINCT a.* 
FROM TEST a 
INNER JOIN TEST b 
ON a.CUSTOMERID = b.CUSTOMERID AND 
a.LOCATION <> b.LOCATION; 

Однако решение проблемы, такие как шахты с двумя колоннами, имеющие соответствующими значениями в нескольких строках (2 в данном случае, не дадут никаких результатов, потому что все PurchaseID являются уникальными):

SELECT DISTINCT a.* 
FROM TEST a 
INNER JOIN TEST b 
ON a.CUSTOMERID = b.CUSTOMERID AND 
a.PURCHASEID = b.PURCHASEID AND 
a.LOCATION <> b.LOCATION; 

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

SELECT DISTINCT a.* 
FROM TEST a 
INNER JOIN TEST b 
ON a.CUSTOMERID = b.CUSTOMERID AND 
a.PURCHASEID <> b.PURCHASEID AND 
a.LOCATION = b.LOCATION; 

Если кто-то хочет попробовать в Oracle здесь таблица и значения для ввода:

CREATE TABLE TEST (
PurchaseID integer, 
CustomerID integer, 
Location varchar(1)); 

INSERT ALL 
    INTO TEST VALUES (1, 1, 'A') 
    INTO TEST VALUES (2, 1, 'A') 
    INTO TEST VALUES (3, 2, 'A') 
    INTO TEST VALUES (4, 2, 'B') 
    INTO TEST VALUES (5, 2, 'A') 
    INTO TEST VALUES (6, 3, 'B') 
    INTO TEST VALUES (7, 3, 'B') 
SELECT * FROM DUAL; 
Смежные вопросы