2016-11-28 4 views
3

У нас есть группа пациентов в одном столе, и мы хотим, чтобы каждый из них соответствовал каждому пациенту точно так же, как и в другой таблице, но мы хотим пары пациентов, чтобы мы не могли сопоставить пациента с более чем одним пациентом.Есть ли какой-либо способ в Google Big Query to Left Outer Присоединиться один на один * без повторного использования * любой строки справа?

Левые внешние соединения добавляют каждое совпадение - что соответствует пациентам для любого другого возможного совпадения - так что нам нужен другой подход.

Мы видим много ответов на вопрос о сопоставлении с первым рядом, но это оставляет нас с одним пациентом, который подходит нескольким другим пациентам - не такая пара, как нам нужна.

Есть ли какой-либо возможный способ создания парных совпадений без дублирования между таблицами в Google Big Query? (Даже если это займет несколько шагов.)


ADDENDUM: Вот пример таблицы. Было бы здорово увидеть пример SQL, используя это.

Вот что необходимо.

Example Source Tables: 

Table A 
PatientID  Race  Gender  
    1   A  F 
    2   B  M 
    3   A  F 

Table B 
PatientID 
    4   A  F 
    5   A  F 
    6   B  M 


Results Table Desired: 

Table C 
A.PatientID  B.PatientID_Match 
    1    4 
    2    6 
    3    5 

РАЗЪЯСНЕНИЕ: Пациенты в таблице A должны соответствовать пациентам из таблицы B. (они не могут сравниться пациентами в их собственной таблице.)

+1

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

+2

поставляют кучу данных образца и ожидаемых результатов. Google Cloud Sql - это всего лишь мария, поскольку они хотят избежать ценообразования на предприятиях mysql и прокладывать себе путь. Помимо этого, нет необходимости упоминать Google ни в одном из этих (как я ее вижу). – Drew

+0

В каждой таблице просто назначьте каждого пациента ранг. Соедините каждого пациента в таблице_a с пациентом с соответствующим рангом в таблице_b – Strawberry

ответ

1

Во многих базах данных, боковые присоединиться бы быть путь. В Google вы можете использовать row_number(). Запрос выглядит примерно так:

select p.*, pp.patient_id as other_patient_id 
from patients p cross join 
    (select p.*, 
      row_number() over (partition by col1, col2, col3 order by col1) as seqnum 
     from patients p 
    ) pp 
where pp.seqnum = 1; 

Столбцы в partition by являются столбцы, используемые для подобия.

+0

Мы просто добавили примеры таблиц, чтобы уточнить результаты, к которым мы стремимся. Используется ли ваш SQL? При первом чтении запрос является бит-привязкой. Были исследования, чтобы лучше понять боковые соединения и ваш код. – Praxiteles

2
select  min (case tab when 'A' then patientID end) as A_patientID 
      ,min (case tab when 'B' then patientID end) as B_patientID 

from  (select tab 
        ,patientID 
        ,rank()  over (order by  race,gender)      r 
        ,row_number() over (partition by tab,race,gender order by patientID) rn 

      from (   select 'A' as tab,A.* from A 
        union all select 'B' as tab,B.* from B 
        ) t 
      ) t 

group by t.r 
      ,t.rn 

-- having  count(*) = 2 
; 

+-------------+-------------+ 
| a_patientid | b_patientid | 
+-------------+-------------+ 
| 3   | 5   | 
+-------------+-------------+ 
| 2   | 6   | 
+-------------+-------------+ 
| 1   | 4   | 
+-------------+-------------+ 

Основная идея -

Строки из обеих таблиц разделены на группы по их признакам (раса, пол).
Это выполняется с использованием функции RANK.

В каждой группе атрибутов (расы, пол) строки упорядочиваются, за стол, их терпеливыми.

+-----+-----------+------+--------+ +---+----+ 
| tab | patientid | race | gender | | r | rn | 
+-----+-----------+------+--------+ +---+----+ 

+-----+-----------+------+--------+ +---+----+ 
| A | 1   | A | F  | | 1 | 1 | 
+-----+-----------+------+--------+ +---+----+ 
| B | 4   | A | F  | | 1 | 1 | 
+-----+-----------+------+--------+ +---+----+ 

+-----+-----------+------+--------+ +---+----+ 
| A | 3   | A | F  | | 1 | 2 | 
+-----+-----------+------+--------+ +---+----+ 
| B | 5   | A | F  | | 1 | 2 | 
+-----+-----------+------+--------+ +---+----+ 

+-----+-----------+------+--------+ +---+----+ 
| A | 2   | B | M  | | 5 | 1 | 
+-----+-----------+------+--------+ +---+----+ 
| B | 6   | B | M  | | 5 | 1 | 
+-----+-----------+------+--------+ +---+----+ 

В конечной фазе, строки быть разделены на группы (GROUP BY) их RANK (г) и значений ROW_NUMBER (Rn), что означает каждая группа имеет строку из каждой таблицы (или только одна строка, если нет соответствующей строки из другой таблицы).

+0

@onedaywhen, возможно, вы этого не поняли, потому что это было на самом деле неправильно :-) –

+0

@DuduMarkovitz Это звучит интригующе - хотя нам не хватает, как увидеть результаты матча. Например, идентификатор пациента 6 должен соответствовать идентификатору пациента 2. Как мы видим это соответствие в таблице результатов, которую генерирует ваш SQL? Ой, подождите, похоже, вы сопоставляете пары строк? (От 1-й до 2-й строки, от 3-й строки до 4-й строки) ... и т. Д. – Praxiteles

+0

@DuduMarkovitz Хорошо - я думаю, мы понимаем это сейчас, но есть одна проблема - пациенты должны сопоставлять * через * таблицы. Похоже, что в этом подходе пациенты в таблице A сопоставляются с пациентами в одной таблице (в отличие от пациентов, которых сравнивают с пациентами в таблице B.) Есть ли способ обеспечить соответствие матчей по столам? – Praxiteles

0
SELECT 
    a.PatientID AS PatientID, 
    b.PatientID AS PatientID_Match 
FROM (
    SELECT PatientID, Race, Gender, 
    ROW_NUMBER() OVER(PARTITION BY Race, Gender) AS Pos 
    FROM TableA 
) AS a 
JOIN (
    SELECT PatientID, Race, Gender, 
    ROW_NUMBER() OVER(PARTITION BY Race, Gender) AS Pos 
    FROM TableB 
) AS b 
ON a.Race = b.Race AND a.Gender = b.Gender AND a.Pos = b.Pos 

Над оставят из тех пациентов, из TableA, которые либо не имеют аналогов в TableB или потенциальном матче в TableB уже использовали в качестве матча для другого пациента в TableA (согласно вашему we want pairs of patients so we cannot match a patient to more than one other patient. требованию)

Для адрес Dudu's comments about NULL для атрибутов:

SELECT 
    a.PatientID AS PatientID, 
    b.PatientID AS PatientID_Match 
FROM (
    SELECT 
    PatientID, IFNULL(Race, 'null') AS Race, IFNULL(Gender, 'null') AS Gender, 
    ROW_NUMBER() OVER(PARTITION BY Race, Gender) AS Pos 
    FROM TableA 
) AS a 
JOIN (
    SELECT 
    PatientID, IFNULL(Race, 'null') AS Race, IFNULL(Gender, 'null') AS Gender, 
    ROW_NUMBER() OVER(PARTITION BY Race, Gender) AS Pos 
    FROM TableB 
) AS b 
ON a.Race = b.Race AND a.Gender = b.Gender AND a.Pos = b.Pos 
+0

Этот метод не обрабатывает нулевые атрибуты –

+0

как нулевой смысл здесь? null как гонки? null как пол? пациенты с нулевыми атрибутами? –

+0

Возможно, да, возможно нет. Если 2 записи, которые являются равными в некоторых атрибутах и ​​имеют нули для остальных атрибутов, считаются совпадением с OP, это решение не будет обрабатывать их. –