T- SQL sub select для извлечения строк со столбцами, которые имеют значения вместо NULL - PullRequest
0 голосов
/ 11 января 2020

Этот пример настолько близок, насколько я могу продемонстрировать для проблемы, которую я пытаюсь решить. В этом случае суб-выбор имеет несколько в основном дублированных строк, с той лишь разницей, что некоторые имеют delvieryDate, а некоторые - НЕ. Если имеется строка данных с датой, я хочу это. Если нет, мне нужно получить строку без даты. Я попытался исправить суб-выбор с помощью «Top 1» и «Order by dDate des c», но T- SQL не разрешит Order by в суб-выборе.

Для этого примера Я хочу строку 9 вместо строки 8, так как у предыдущего есть дата. Я также хочу строку 10, поскольку нет эквивалента с датой.

enter image description here

Код:

Create Table #Customer (
    CustomerId int,
    cName nvarchar(100),
    Address nvarchar(100),
)

INSERT INTO #Customer
VALUES (1, 'Bill', '123 1st St'),
       (2, 'Fred', '111 Market St'),
       (3, 'Lisa', '01 Boulevard')

Create Table #MealType (
    MealTypeId  int,
    mName nvarchar(100)
)
INSERT INTO #MealType
VALUES (1, '1 - Breakfast'), (2, '2 - Lunch'), (3, '3 - Dinner')

Create Table #Food (
    FoodId  int,
    fName nvarchar(100),
    Restaurant nvarchar(100),
    MealType_fk int
)
INSERT INTO #Food
VALUES (3, 'Bacon & Egg Biscut', 'McDs',1),
       (2, 'Happy Meal', 'McDs', 2),
       (1, 'Pizza', 'Dominos', 3),
       (4, 'Santa Fe Salad', 'GrubHub', 2)

Create Table #Delivery (
    DeliveryId  int,
    FoodId_fk int,
    CustomerId_fk int,
    dDate datetime
)
INSERT INTO #Delivery
VALUES (1, 1, 1, CONVERT(date, getdate())),
       (2, 2, 1, CONVERT(date, getdate())),
       (3, 3, 1, CONVERT(date, getdate())),
       (4, 1, 2, CONVERT(date, getdate())),
       (5, 2, 2, CONVERT(date, getdate())),
       (6, 3, 2, CONVERT(date, getdate())),
-- removed data (7, 1, 3, CONVERT(date, getdate())),
       (8, 4, 3, CONVERT(date, getdate())),
       (9, 3, 3, CONVERT(date, getdate())),
      (10, 1, 3, NULL),
      (12, 4, 3, NULL)

select
    c.cName,
    c.Address,
    f.Restaurant,
    f.fName,
    m.mName,
    convert(varchar, d.dDate, 103) as dDate
from #customer c
left join (select distinct
               FoodId_fk,
               CustomerId_fk,
               dDate
           from #Delivery
           ) as d on c.CustomerId = d.CustomerId_fk
join #Food f on d.FoodId_fk = f.FoodId
join #MealType m on f.MealType_fk = m.MealTypeId
order by cName, mName

Ответы [ 2 ]

1 голос
/ 11 января 2020

Можно также начать с предоставленного вами выходного набора данных (назовите его #have). Существует типичный быстрый и грязный способ выбрать максимальное значение с помощью ROW_NUMBER() (доступно в SQL Server 2005 и выше).

Преимущество метода заключается в том, что вы можете уменьшить количество сравниваемых столбцов (определено в partition by). Это невозможно сделать с помощью простого оператора group by, поскольку у вас не может быть выходных столбцов, кроме групповых или агрегатных переменных.

Недостатком является эффективность. Ответ @GMB явно предпочтительнее, когда это применимо. Также рассмотрим с использованием перекрестного применения вместо для большого набора данных.

Код:

with T as (
    select *,
        ROW_NUMBER() over(partition by cName, [Address], Restaurant, fName, mName
                          order by dDate desc) as rn
    from #have
)
select cName, [Address], Restaurant, fName, mName, dDate
from T
where rn = 1
order by cName, mName;

Вывод:

cName   Address         Restaurant fName                 mName           dDate
Bill    123 1st St      McDs       Bacon & Egg Biscut    1 - Breakfast   11/01/2020
Bill    123 1st St      McDs       Happy Meal            2 - Lunch       11/01/2020
Bill    123 1st St      Dominos    Pizza                 3 - Dinner      11/01/2020
Fred    111 Market St   McDs       Bacon & Egg Biscut    1 - Breakfast   11/01/2020
Fred    111 Market St   McDs       Happy Meal            2 - Lunch       11/01/2020
Fred    111 Market St   Dominos    Pizza                 3 - Dinner      11/01/2020
Lisa    01 Boulevard    McDs       Bacon & Egg Biscut    1 - Breakfast   11/01/2020
Lisa    01 Boulevard    GrubHub    Santa Fe Salad        2 - Lunch       11/01/2020
Lisa    01 Boulevard    Dominos    Pizza                 3 - Dinner      NULL
1 голос
/ 11 января 2020

Для этих данных одним из вариантов будет использование агрегирования, используя тот факт, что функции агрегирования игнорируют null значения:

select
    c.cName,
    c.Address,
    f.Restaurant,
    f.fName,
    m.mName,
    convert(varchar, max(d.dDate), 103) as dDate
from #customer c
join #Delivery d on c.CustomerId = d.CustomerId_fk
join #Food f on d.FoodId_fk = f.FoodId
join #MealType m on f.MealType_fk = m.MealTypeId
group by
    c.cName,
    c.Address,
    f.Restaurant,
    f.fName,
    m.mName
order by cName, mName

Демонстрация на DB Fiddle :

cName | Address       | Restaurant | fName              | mName         | dDate     
:---- | :------------ | :--------- | :----------------- | :------------ | :---------
Bill  | 123 1st St    | McDs       | Bacon & Egg Biscut | 1 - Breakfast | 11/01/2020
Bill  | 123 1st St    | McDs       | Happy Meal         | 2 - Lunch     | 11/01/2020
Bill  | 123 1st St    | Dominos    | Pizza              | 3 - Dinner    | 11/01/2020
Fred  | 111 Market St | McDs       | Bacon & Egg Biscut | 1 - Breakfast | 11/01/2020
Fred  | 111 Market St | McDs       | Happy Meal         | 2 - Lunch     | 11/01/2020
Fred  | 111 Market St | Dominos    | Pizza              | 3 - Dinner    | 11/01/2020
Lisa  | 01 Boulevard  | McDs       | Bacon & Egg Biscut | 1 - Breakfast | 11/01/2020
Lisa  | 01 Boulevard  | GrubHub    | Santa Fe Salad     | 2 - Lunch     | 11/01/2020
Lisa  | 01 Boulevard  | Dominos    | Pizza              | 3 - Dinner    | <em>null</em>      
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...