Как отличить нуль от несоответствующей записи и нуль от несуществующей записи в левом соединении? - PullRequest
1 голос
/ 06 апреля 2019

Приведенные ниже операторы создают таблицы, данные и выборку, в которой возникла проблема.

Цель состоит в том, что при отсутствии заказов для custid 1 я хочу отобразить «Не найдено заказов», и еслиесть записи заказа для custid 1, но не для телевизора, я хочу отобразить «Найден заказ, но не заказ телевизора».В обоих случаях t.description будет NULL, но мне нужно различать два NULL-случая.Как различить их, чтобы первые два оператора WHEN могли обрабатывать каждый из них соответственно?

CREATE TABLE [dbo].[Customer](
    [CustId] [int] NOT NULL,
    [CustomerName] [varchar](50) NOT NULL
)

CREATE TABLE [dbo].[Order](
    [OrderId] [int] NOT NULL,
    [CustId] [int] NOT NULL,
    [Description] [varchar](50) NOT NULL
)



INSERT INTO customer (CustId, CustomerName) VALUES
(1, 'John'),
(2, 'Tom')
GO

INSERT INTO [order] (OrderId, CustId, Description) VALUES
(1, 2, 'TV')
go

IF OBJECT_ID('tempdb..#temp') IS NOT NULL
    DROP TABLE #temp;

SELECT

    'TV' Description INTO #temp

SELECT c.CustId
    ,t.Description
   ,o.Description
   ,CASE
        WHEN t.Description IS NULL THEN 'Did not find any orders'
        WHEN t.Description IS NULL THEN 'Found order but not TV order'
        ELSE 'Found TV Order' 
    END Status

FROM Customer c
LEFT JOIN [Order] o
    ON o.CustId = c.CustId
LEFT JOIN #temp t
    ON t.Description = o.Description
WHERE c.CustId = 1

ОБНОВЛЕНИЕ:

В таблице #temp есть критерии для поиска,В данном случае «ТВ».

Ответы [ 5 ]

1 голос
/ 06 апреля 2019

Если вы просто хотите отобразить информацию о клиенте, используйте агрегирование:

SELECT c.CustId,
       (CASE WHEN COUNT(o.CustId) = 0
             THEN 'Did not find any orders'
             WHEN SUM(CASE WHEN o.Description = 'TV' THEN 1 ELSE 0 END) = 0
            THEN 'Found order but not TV order'
            ELSE 'Found TV Order' 
       END) as Status
FROM Customer c LEFT JOIN 
     [Order] o
     ON o.CustId = c.CustId
WHERE c.CustId = 1
GROUP BY c.CustId;

Обратите внимание, что я понятия не имею, для чего используется #temp.

Также выне следует включать информацию об уровне заказа в SELECT, если вы хотите получить информацию на уровне клиента.

0 голосов
/ 06 апреля 2019

Во-первых, я предполагаю, что в таблице «Заказ» может и, скорее всего, будет несколько записей на одного клиента.Так как вам нужно знать, нет ли каких-либо заказов, но, по-видимому, нужен набор результатов, вы не можете отфильтровать на основе желаемого описания ... Но вы можете, если вы группируете по клиенту (и описанию) и используете счетфункция, и это также позволяет вам возвращать одну запись, когда их может быть много в таблице Order.

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

Вот SQL (я сделал временную таблицу постоянной для этого, а также добавил больше записей):

CREATE TABLE [dbo].[Customer](
    [CustId] [int] NOT NULL,
    [CustomerName] [varchar](50) NOT NULL
)
CREATE TABLE [dbo].[Order](
    [OrderId] [int] NOT NULL,
    [CustId] [int] NOT NULL,
    [Description] [varchar](50) NOT NULL
)
CREATE TABLE [dbo].[FakeTemp](
    [Description] [varchar](50) NOT NULL
)
INSERT INTO FakeTemp (Description) VALUES
('TV')
GO
INSERT INTO customer (CustId, CustomerName) VALUES
(1, 'John'),
(2, 'Tom'),
(3, 'Steve')
GO
INSERT INTO [order] (OrderId, CustId, Description) VALUES
(1, 1, 'TV')
go
INSERT INTO [order] (OrderId, CustId, Description) VALUES
(2, 2, 'VCR')
go
INSERT INTO [order] (OrderId, CustId, Description) VALUES
(3, 1, 'VCR')
go


select c.CustomerName, count(OrderId) as TV_Orders
, (select count(OrderID) from [order] where CustId = 1) as All_Orders
from customer c
left outer join [order] o on c.CustId = o.CustId
inner join FakeTemp t on o.Description = t.Description
where c.CustID = 1
group by c.CustomerName, t.Description

А вот ссылкана скрипку (спасибо Роману Пекару за то, что он меня запустил): http://sqlfiddle.com/#!18/eadc3/16/0

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

Для тех, кто не смог завершить описание дела, вот домашняя задача, выполненная полностью:

select
  CASE
      WHEN (select count(OrderID) from orders where CustId = 1) = 0 THEN 'Did not find any orders'
      WHEN count(OrderID) = 0 THEN 'Found order but not TV order'
      ELSE 'Found TV Order'
  End as Status

from customer c
left outer join [orders] o on c.CustId = o.CustId
inner join FakeTemp t on o.Description = t.Description
where c.CustID = 1
group by c.CustomerName, t.Description
0 голосов
/ 06 апреля 2019

Это может помочь вам, не уверен.

утверждение о кейсе:

,case when  t.Description = o.Description  then 'Found TV Order'
         when  isnull(t.Description,'No') = isnull(o.Description,'No') then 'Did not find any orders'
         when  isnull(t.Description,'No') <> isnull(o.Description,'No') then 'Found order but not TV order'
   end Status

Измененный запрос:

SELECT c.CustId
    ,t.Description tdesc
   ,o.Description odesc

   ,case when  t.Description = o.Description  then 'Found TV Order'
         when  isnull(t.Description,'No') = isnull(o.Description,'No') then 'Did not find any orders'
         when  isnull(t.Description,'No') <> isnull(o.Description,'No') then 'Found order but not TV order'
   end Status
  /*  ,CASE
        WHEN t.Description IS NULL THEN 'Did not find any orders'
        WHEN t.Description IS NULL THEN 'Found order but not TV order'
        ELSE 'Found TV Order' 
    END Status  */

FROM Customer c
LEFT JOIN [Order] o ON o.CustId = c.CustId
LEFT JOIN #temp t   ON t.Description = o.Description

enter image description here

--------------------------- **Старый код ниже ** ---------------------------------------------

 select CustId,descpt 
    from 
    (
    SELECT c.CustId
        , case when o.Description is null then 'Did not find any orders' end   descpt 
    FROM Customer c
    LEFT JOIN [Order] o ON o.CustId = c.CustId  ) no_orders
    where no_orders.descpt is not null

    union 
    select CustId,descpt 
    from 
    (
    SELECT c.CustId
        , case when o.Description ='TV' then 'Found order for TV ' end   descpt 
    FROM Customer c
    LEFT JOIN [Order] o ON o.CustId = c.CustId  ) no_orders
    where no_orders.descpt is not null

    union
    select CustId,descpt 
    from 
    (
    SELECT c.CustId
        , case when o.Description <> 'TV' then 'Found order but not TV order' end   descpt 
    FROM Customer c
    LEFT JOIN [Order] o ON o.CustId = c.CustId  ) no_orders
    where no_orders.descpt is not null

enter image description here

0 голосов
/ 06 апреля 2019

Из вопроса не совсем понятно, но я предполагаю, что временная таблица #temp - это список описаний, для которых вы хотите посмотреть в заказах.

Так что я могу придумать несколько разных подходов, например, вы можете использовать OUTER APPLY:

select
    c.CustId,
    t.Description,
    case
        when o.Description is null then
            'Did not find any orders'
        when o.Description <> t.Description then
            concat('Found order but not ',t.Description,' order')
        else
            concat('Found ',t.Description,' order')
    end as status
from dbo.Customer as c
    cross join (
        select 'TV' as Description
    ) as t
    outer apply (
        select top 1 tt.Description
        from dbo.[Order] as tt
        where
            tt.CustId = c.CustId
        order by
            case when tt.Description = t.Description then 0 else 1 end
    ) as o

sql fiddle demo

Или вы можете использовать левое соединение и внешнее применение:

select
    c.CustId,
    t.Description,
    case
        when o1.Description is not null then
            concat('Found ',t.Description,' order')
        when o2.OrderId is not null then
            concat('Found order but not ',t.Description,' order')
        else
            'Did not find any orders'
    end as status
from dbo.Customer as c
    cross join (
        select 'TV' as Description
    ) as t
    left join dbo.[Order] as o1 on
        o1.CustId = c.CustId and
        o1.Description = t.Description
    outer apply (
        select top 1 tt.OrderId
        from dbo.[Order] as tt
        where
            tt.CustId = c.CustId and
            tt.Description <> t.Description
    ) as o2

sql fiddle demo

0 голосов
/ 06 апреля 2019

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

 select a.custid,a.CustomerName,orderid=isnull(b.orderId,0),
     description=iif(b.description is null,'Did not Find Any Order',b.description) 
     from Customer a left join [Order] b on a.custid=b.Custid
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...