Простой рефакторинг sql-запроса

#sql #sql-server-2005 #refactoring

#sql #sql-server-2005 #рефакторинг

Вопрос:

У меня есть таблица со строками:

 ID          CountryCode Status
----------- ----------- -----------
2           PL          1
3           PL          2
4           EN          1
5           EN          1
  

и с помощью запроса

 SELECT *
  FROM [TestTable]
  WHERE Status = 1 AND CountryCode NOT IN (SELECT CountryCode
  FROM [TestTable]
  WHERE Status != 1)
  

Я получаю все коды стран, у которых нет значения статуса = 2

 ID          CountryCode Status
----------- ----------- -----------
4           EN          1
5           EN          1
  

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

Как я могу это изменить?

С наилучшими пожеланиями

Редактировать

PL не может быть в результате, поскольку имеет запись со статусом 2

Редактировать

Скрипт для создания и заполнения таблицы:

 USE [DatabaseName]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TestTable](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [CountryCode] [nvarchar](2) NOT NULL,
    [Status] [int] NOT NULL
) ON [PRIMARY]

INSERT INTO dbo.TestTable
          ( CountryCode, Status )
  VALUES  ( 'PL', -- CountryCode - nvarchar(2)
            1  -- Status - int
            )

INSERT INTO dbo.TestTable
          ( CountryCode, Status )
  VALUES  ( 'PL', -- CountryCode - nvarchar(2)
            2  -- Status - int
            )

INSERT INTO dbo.TestTable
          ( CountryCode, Status )
  VALUES  ( 'EN', -- CountryCode - nvarchar(2)
            1  -- Status - int
            )
INSERT INTO dbo.TestTable
          ( CountryCode, Status )
  VALUES  ( 'EN', -- CountryCode - nvarchar(2)
            1  -- Status - int
            )
  

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

1. Являются ли 1 и 2 единственными статусами… или есть и другие, где приложение MIN / MAX может в противном случае завершиться сбоем…

Ответ №1:

Первое: Никогда не используйте SELECT * в часто используемом коде. Особенно в рабочей среде. Вызовите свои столбцы.

Мыльный ящик закончен.

Примечание: я не пробовал это, и в настоящее время у меня не установлена management Studio, поэтому я не могу это протестировать. Но я думаю, вы хотите что-то вроде этого:

 Select Id, CountryCode, Status
From [TestTable] t
Where Status <> 2
And Not Exists(select status from [TestTable] t2 
                             where t2.Status = 2 
                             and t2.CountryCode = tt.CountryCode)
  

По крайней мере, у вас есть правильная идея: если вам нужны только коды стран, которые не соответствуют (ни в одной записи) статусу = 2, вам нужно получить все со статусом 1, а затем исключить все существующие строки, имеющие соответствующую строку со статусом 2. Однако у меня может быть неправильный синтаксис для Not Exists.

Ответ №2:

 select T1.*
from TestTable as T1
  left outer join
    (
      select distinct CountryCode
      from TestTable as T1
      where Status <> 1  
    ) as T2
    on T1.CountryCode = T2.CountryCode
where
  T1.Status = 1 and
  T2.CountryCode is null
  

Ответ №3:

Если вам нужны все записи, в которых Status нет значения 2, попробуйте следующее:

 SELECT *
  FROM [TestTable]
 WHERE Status != 2
  

РЕДАКТИРОВАТЬ: Чтобы предотвратить код страны, в котором любая отдельная запись имеет нежелательное значение, попробуйте предложения GROUP BY и HAVING :

   SELECT CountryCode
    FROM [TestTable]
GROUP BY CountryCode
HAVING MAX(Status) = 1 AND MIN(Status) = 1
  

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

1. Я обновил свой ответ запросом, который позволяет избежать явных вложенных запросов и объединений

2. Это не сработает, поскольку T-SQL требует, чтобы столбцы group by использовались в агрегатной функции или перечислялись в предложении group by. Что вы думаете о MySQL?

3. Ура, командная работа! У меня нет SQL server 2005, на котором я мог бы это протестировать, но небольшое сотрудничество имеет большое значение 🙂

Ответ №4:

  SELECT distinct(country) FROM table WHERE value <> 2