CTE-общая таблица exp в t-sql - PullRequest
       28

CTE-общая таблица exp в t-sql

0 голосов
/ 30 августа 2011

У меня проблема со следующим запросом:

WITH CTE_1 (stu_id
            ,meet_doc_id
            ,doc_name
            ,stu_name
            ,dob
            ,done
            ,date_meet_doc)
AS

(SELECT stu_id
        ,meet_doc_id
        ,doc_name
        ,stu_name
        ,dob
        ,CASE
              WHEN (PATINDEX('%SMOKING%',act.VALUE)) THEN 
                           'LMDO'                       
              WHEN (PATINDEX('%NOT SMOKING%',act.VALUE)) THEN  
                            'LMD1'                       
              WHEN (ISNULL(CAST(act.VALUE as varchar(max)),'')='') THEN     
                            'CLEAR'                       
              ELSE                                   
                            'CLEAR'    
              END done 
        ,date_meet_doc

FROM 
abc INNER JOIN
INNER JOIN 
INNER JOIN 
WHERE multiple conditions
)

SELECT * FROM CTE_1 one
WHERE date =(SELECT MAX(DATE) FROM CTE_1 two WHERE two.stu_id=one.stu_id
AND one.doc_name=two.doc_name)
ORDER BY stu_name,dob
;

Результирующий набор внутреннего запроса (CTE_1) для трех учеников (например, для) будет выглядеть примерно так:

stu_id   meet_doc_id   doc_name   stu_name      dob        value      date
101        0104          AD          AM      15/06/1950     LMDO     2011-02-15
101        0105          AD          AM      15/06/1950     CLEAR    2011-02-18
101        0106          AD          AM      15/06/1950     CLEAR    2011-02-25
102        0107          AD          AK      12/08/1987     CLEAR    2011-03-28
102        0108          AD          AK      12/08/1987     LDMO     2011-04-29
103        0109          PK          LMP     13/07/1970     CLEAR    2011-03-28
103        0110          PK          LMP     13/07/1970     CLEAR    2011-05-12

И когда я выполню весь запрос, мой набор результатов будет

stu_id   meet_doc_id   doc_name   stu_name      dob         value      date
101        0106          AD          AM      15/06/1950     CLEAR    2011-02-25
102        0108          AD          AK      12/19/1987     LDMO     2011-04-29
103        0110          PK          LMP     13/07/1970     CLEAR    2011-05-12

Что мне нужно сделать, чтобы изменить внешний запрос, чтобы выбрать только те значения, т. Е. LDMO или LMD1 для конкретного студента и чей врач такой же?

Предположим, что если студент встречается с документом несколько раз, и если в каком-либо из случаев студент получает LMDO или LMD1, он должен выбрать только эту запись независимо от даты.

Я ожидаю, что мой набор результатов будет примерно таким:

stu_id   meet_doc_id   doc_name   stu_name      dob         value      date
101        0104          AD          AM      15/06/1950     LMDO     2011-02-15
102        0107          AD          AK      12/08/1987     CLEAR    2011-03-28
103        0110          PK          LMP     13/07/1970     CLEAR    2011-05-12

Логика заключается в том, что если stu_id одинаков и doc_name одинаково, и если существует значение либо LMDO, либо LMD1, то покажите эту запись, если не покажите запись с CLEAR. Просто я хочу удалить МАКС (дата) и поместить условие на весь отчетный период этого конкретного stu_id с тем же именем документа.

Ответы [ 2 ]

1 голос
/ 02 сентября 2011
declare @TestTable
as table
(stu_id int,
 meet_doc_id  char(4), 
 doc_name  char(2), 
 stu_name  varchar(3),   
 dob date,
 value  varchar(5),
 date_meet_doc date)

insert into @TestTable
(stu_id,meet_doc_id,doc_name,stu_name,dob,value,date_meet_doc)
values
(101,'0104','AD','AM', '19500615','LDMO' ,'2011-02-15'),
(101,'0105','AD','AM', '19500615','CLEAR','2011-02-18'),
(101,'0106','AD','AM', '19500615','CLEAR','2011-02-25'),
(102,'0107','AD','AK', '19870812','CLEAR','2011-03-28'),
(102,'0108','AD','AK', '19870812','LDMO' ,'2011-04-29'),
(103,'0109','PK','LMP','19700713','CLEAR','2011-03-28'),
(103,'0110','PK','LMP','19700713','CLEAR','2011-05-12');

WITH CTE_1 (stu_id
                ,meet_doc_id
                ,doc_name
                ,stu_name
                ,dob
                ,done
                ,date_meet_doc)
    AS

    (SELECT stu_id
            ,meet_doc_id
            ,doc_name
            ,stu_name
            ,dob
            ,value
            ,date_meet_doc

    FROM @TestTable
    ),
    CTE_2 as(
    SELECT *,row_number() over (partition by stu_id order by  case when done in ('LDMO','LDM1') then 0 else 1 end, date_meet_doc desc) rn FROM CTE_1) 
    select stu_id
            ,meet_doc_id
            ,doc_name
            ,stu_name
            ,dob
            ,value
            ,date_meet_doc
    from CTE_2 where rn=1
    ;

Спасибо тем, кто пытался понять, но сдался, потому что я не мог этого объяснить. Еще раз спасибо, ребята:)

1 голос
/ 31 августа 2011

Редактировать : Добавить описание высокого уровня того, что я сделал.

Вы хотите получить исходную информацию (CTE_1), отфильтрованную по 2 возможным критериям.Самый простой способ сделать это - сначала установить эти критерии в их собственных наборах результатов.Итак, у нас есть подзапрос, который возвращает список (Student, Doc, Max(Date)) комбинаций и аналогичный список, отфильтрованный по значениям LMDO/LMD1.

Теперь нам нужно LEFT JOIN отфильтрованных данных, так как можетне может быть результатов для каждого учащегося.

Итак, теперь у вас есть список Student/Doc/MaxDate, а также возможный FilteredDate.

Последний шаг - JOIN тот результат, который установлен висходные данные (CTE_1).Поскольку FilteredDate имеет приоритет, мы сначала проверяем это с помощью функции ISNULL и, если она отсутствует, вместо этого используем MaxDate.


Сначала я бы изменил исходный запроск следующему, так как я думаю, что вы увидите некоторое повышение производительности для больших наборов данных, исключив коррелированный подзапрос:

SELECT * 
FROM CTE_1 one
INNER JOIN 
  (SELECT stu_id, doc_name, max(date) maxdate FROM CTE_1 group by stu_id,doc_name) two
  ON one.stu_id = two.stu_id and one.doc_name = two.doc_name
ORDER BY stu_name,dob

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

SELECT realdata.* 
FROM 
  ((SELECT stu_id, doc_name, max(date) maxdate FROM CTE_1 group by stu_id,doc_name) maxdt
LEFT JOIN 
  (SELECT stu_id, doc_name, max(date) maxdate FROM CTE_1 
   WHERE value in ('LMDO', 'LMD1')
   group by stu_id,doc_name) filtered
  ON maxdt.stu_id = filtered.stu_id and maxdt.doc_name = filtered.doc_name)
INNER JOIN CTE_1 realdata
  ON realdata.stu_id = maxdt.stu_id and realdata.doc_name = maxdt.doc_name
     and realdata.date = isnull(filtered.maxdate, maxdt.maxdate)
ORDER BY realdata.stu_name,realdata.dob
...