Как я могу исправить этот запрос для записей, которые соответствуют ОБОИМ условиям?

#sql #sql-server

#sql #sql-сервер

Вопрос:

Я новичок в SQL Server. Мне нужно отфильтровать запрос, но я не уверен, как. В моем запросе есть соединения, которые я опустил здесь для простоты.

 SELECT Name, Date
FROM my_table AS C
WHERE Date = '2019-04-15' AND Date IS NULL
  

В My_table есть такие данные:

 Name    Date
---------------------
John    2019-04-01
Ally    2019-04-01
Steve   NULL
James   2019-04-15
James   NULL
  

Если я выполняю запрос для любого из условий where, я получаю ожидаемые результаты только для одного условия. Но добавление И не дает результатов. Использование ИЛИ дает мне последние 3 записи. Но то, что я ищу, это отфильтровать его, чтобы я просто видел последние 2 записи, поскольку у Джеймса есть запись, которая соответствует дате, а также запись с НУЛЕВОЙ датой.

Как я могу отфильтровать имена, которые соответствуют ОБОИМ условиям? Заранее спасибо.

Комментарии:

1. Вероятно, вы хотите OR , не AND : Date = '2019-04-15' OR Date IS NULL

2. «Использование ИЛИ дает мне последние 3 записи. Но то, что я ищу, это отфильтровать его, чтобы я просто видел последние 2 записи, поскольку у Джеймса есть запись, которая соответствует дате, а также запись с нулевой датой.»

3. Итак, вам нужны только строки для James? Почему вы не фильтруете с помощью WHERE name = ‘James’

4. ForpasI — t не всегда является Джеймсом, которого я ищу. Я ищу все имена, в которых есть строка с определенной датой, и строку с тем же именем с НУЛЕВОЙ датой.

5. И почему вы не упомянули об этом в своем вопросе?

Ответ №1:

Вы могли бы попробовать это:

 SELECT a.name
FROM   my_table a
JOIN   my_table b
  ON   a.name = b.name
 AND   b.date IS NULL
WHERE  a.date = '2019-04-15';
  

Конечно, если существует несколько записей для определенного имени с NULL датой, вы получаете несколько результатов.

Это можно решить следующим образом:

 SELECT a.name
FROM   my_table a
WHERE  a.date = '2019-04-15'
  AND  EXISTS (SELECT *
               FROM   my_table b
               WHERE  a.name = b.name
                 AND  b.date IS NULL);
  

Ответ №2:

Из ваших комментариев:

Я ищу все имена, в которых есть строка с определенной датой, и строку с тем же именем с НУЛЕВОЙ датой

Вы можете сделать это с помощью EXISTS:

 select name 
from my_table t
where 
  date = '2019-04-15'
  and exists (
    select 1 from my_table
    where name = t.name and date is null
  )
  

Редактировать
Если вам нужны как строка с ненулевой датой, так и строка с нулевой датой:

 select t.* 
from my_table t
where ( 
  date = '2019-04-15'
  and exists (
    select 1 from my_table
    where name = t.name and date is null
  )
) or (
  date is null
  and exists (
    select 1 from my_table
    where name = t.name and date = '2019-04-15'
  )  
)
  

Смотрите демонстрацию

Комментарии:

1. Я пытаюсь это сделать. Мне просто нужно выяснить, как обернуть его с помощью имеющихся у меня объединений.

2. Наконец-то появилось время попробовать это. Я не знал о предложении EXISTS . После попытки я получаю только даты 4/15 и, похоже, игнорирую условие NULL. У меня есть соединения с обоими операторами select. Оба предложения where независимо выдают мне соответствующие отфильтрованные результаты. Но EXISTS ничего не делает для изменения результатов из первого предложения WHERE. Я подозреваю, что это как-то связано с тем, как я внедряю ваше решение. Я продолжу работать с ним.

3. Попробуйте обернуть свой запрос (без моего кода) внутри CTE и применить мой код к cte, например: with cte as (<your query>) select distinct name from cte t where date is not null and exists (select 1 from cte where name = t.name and date is null )

4. Извините, что так долго возвращаюсь к этому. Итак, я вложил свой запрос в ваш cte. Результаты представляют собой список уникальных имен с датой 4/15. Имена с нулевым значением исключаются. (Я изменил свой исходный опубликованный запрос, чтобы использовать AND вместо OR.)

5. Итак, вам нужны также строки со значением pair null, верно?

Ответ №3:

Попробуйте это:

 SELECT 
    Name, 
    Date,
    COUNT(C.Date)
FROM my_table AS C

having COUNT(C.Date) > 1
group by
    Name, 
    Date
  

Ответ №4:

 SELECT 
    Name, 
    Date,
    COUNT(temp.Date)
FROM my_table AS temp
where temp.Date = '2019-04-15' OR temp.Date IS NULL
having COUNT(temp.Date) > 1
group by
    Name, 
    Date
  

Ответ №5:

Если вам нужна строка, которая также имеет нулевое значение, вы можете попробовать ниже.

 SELECT m.name,m.Date
FROM   my_table m
WHERE  (m.date = '2019-04-15' OR m.date IS NULL
AND  EXISTS (SELECT 1
           FROM   my_table im
           WHERE  m.name = im.name
             AND  im.date IS NOT NULL))
  

Этого также можно достичь с помощью SELF JOIN.

 SELECT DISTINCT m.name,m.Date
FROM   my_table m
INNER JOIN my_table im ON im.Name = m.Name
WHERE  (m.date = '2019-04-15' OR m.date IS NULL
 AND im.Date IS NOT NULL)
  

Комментарии:

1. Я пробовал варианты EXIST с другими ответами, но безрезультатно. Ваш немного отличается, ваш выдает мне список всех имен с нулевой датой и всех имен с датой, мало чем отличающийся от простого добавления DISTINCT в первую строку SELECT. Если я понимаю предложение EXiSTS , оно гласит «Дайте мне имена и записи 4/15, а теперь покажите мне, какие из них в этом результате не являются нулевыми?» Это почти так, как будто мне нужно выполнить 2 запроса, а затем третий, чтобы сопоставить имена, найденные в обоих.

2. Да, он говорит, дайте мне имена и даты, где date = ‘2019-04-15’ или date равно null, а затем снова просмотрите таблицу, чтобы увидеть, совпадает ли имя с выбранными строками.