2016-01-11 3 views
3

ПроблемаИспользование HAVING или WHERE на SUM Поля

У нас есть таблица пользователей и адресов table.Each пользователь может иметь несколько адресов. У нас есть поле бит под названием IsDefault, где пользователь может выбрать свой адрес по умолчанию. Это поле в настоящее время не является обязательным и, возможно, будет в будущем, поэтому мне нужно сделать некоторый анализ. Теперь я хочу подтвердить адреса, чтобы увидеть:

  • Сколько адресов у данного пользователя.
  • Сколько из этих адресов (если они имеют более 1 адрес) имеет флаг IsDefault установлен в 1.

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

У меня есть следующий запрос SQL до сих пор:

SELECT AD.User_Id, 
     COUNT(AD.User_Id) AS HowManyAddresses, 
     SUM(
      CASE WHEN 
       AD.IsDefault IS NULL 
       OR 
       AD.IsDefault = 0 
      THEN 
       1 
      ELSE 
       0 
      END 
     ) AS DefaultEmpty, 

     SUM(
      CASE WHEN 
       AD.IsDefault = 1 
      THEN 
       1 
      ELSE 
       0 
      END 
     ) AS DefaultAddress 

FROM dbo.Addresses AS AD 
    JOIN dbo.Users AS U 
    ON U.Id = AD.User_Id 
GROUP BY AD.User_ID 
ORDER BY AD.User_Id 

Проблема, которую я нашел, я хочу, чтобы проверить значение от DefaultAddress и DefaultEmpty выбора полого SUM, но я получаю следующее сообщение об ошибке при попытке ссылайтесь на них, используя WHERE или HAVING:

Недопустимое имя столбца 'DefaultEmpty'.

Нельзя ли использовать значения SUM для выбора?

Технология использования:

  1. SQL Server 2008
  2. SQL Server Management Studio 2008
+1

Можно использовать значения SUM, но вы не можете ссылаться на псевдонимы столбцов в предложениях where или having, поэтому вам придется повторно набирать совокупность, например. 'ИМЕЕТ СУММУ (СЛУЧАЙ, КОГДА AD.IsDefault IS NULL ИЛИ AD.IsDefault = 0 THEN 1 ELSE 0 END)> 1'. Предложение 'SELECT' находится после предложения' WHERE/HAVING' с [Логическим порядком обработки] (https://msdn.microsoft.com/en-us/library/ms189499.aspx), поэтому, когда оба выполняются эти столбцы псевдонимы еще не определены. – GarethD

ответ

1

На самом деле вам нужно повторить весь SUM пункт с HAVING как это -

SELECT 
    AD.User_Id 
    ,COUNT(AD.User_Id) AS HowManyAddresses 
    ,SUM(
    CASE 
     WHEN 
      AD.IsDefault IS NULL OR 
      AD.IsDefault = 0 THEN 1 
     ELSE 0 
    END 
    ) AS DefaultEmpty 
    ,SUM(
    CASE 
     WHEN 
      AD.IsDefault = 1 THEN 1 
     ELSE 0 
    END 
    ) AS DefaultAddress 

FROM dbo.Addresses AS AD 
JOIN dbo.Users AS U 
    ON U.Id = AD.User_Id 
GROUP BY AD.User_ID 
HAVING SUM(
CASE 
    WHEN 
     AD.IsDefault IS NULL OR 
     AD.IsDefault = 0 THEN 1 
    ELSE 0 
END 
) = 0 
ORDER BY AD.User_Id 

ИЛИ

DECLARE @address TABLE(UserID INT,Address VARCHAR(100),IsDefault BIT); 
INSERT INTO @address VALUES 
(1,'User 1 default',1) 
,(2,'User 2 non default',0) 
,(3,'User 3 non default',0) 
,(3,'User 3 default',1) 
,(4,'User 4 default',1) 
,(4,'User 4 second default',1); 

SELECT 
    COUNT(*) OVER() AS HowManyAddresses 
    ,ISNULL(def0.DefaultEmpty, 0) AS DefaultEmpty 
    ,ISNULL(def1.DefaultAddress, 0) AS DefaultAddress 
FROM (SELECT 
     AD.Address 
     ,COUNT(AD.UserID) OVER (PARTITION BY AD.UserID) AS DefaultEmpty 
    FROM @address AS AD 
    WHERE (AD.IsDefault = 0)) def0 
FULL JOIN (SELECT 
     AD.Address 
     ,COUNT(AD.UserID) OVER (PARTITION BY AD.UserID) AS DefaultAddress 
    FROM @address AS AD 
    WHERE (AD.IsDefault = 1)) def1 
    ON def0.Address = def1.Address 
1

Это COUNT - сгруппированы пользователем и по умолчанию, сколько адресов есть:

DECLARE @user TABLE(ID INT, Name VARCHAR(100)); 
INSERT INTO @user VALUES 
(1,'user1') --will get a default 
,(2,'user2') --no default 
,(3,'user3') --both 
,(4,'user4') --two defaults 
,(5,'user5');--nothing 

DECLARE @address TABLE(UserID INT,Address VARCHAR(100),IsDefault BIT); 
INSERT INTO @address VALUES 
(1,'User 1 default',1) 
,(2,'User 2 non default',0) 
,(3,'User 3 non default',0) 
,(3,'User 3 default',1) 
,(4,'User 4 default',1) 
,(4,'User 4 second default',1); 

EDIT: Лучше с PIVOT ...

SELECT p.* 
FROM 
(
    SELECT u.ID,u.Name 
      ,CASE WHEN a.IsDefault=1 THEN 'DEFAULT' ELSE 'NORMAL' END AS PivotColumn 
      ,COUNT(a.UserID) AS CountPerUserAndDefault 
    FROM @user AS u 
    LEFT JOIN @address AS a ON u.ID=a.UserID 
    GROUP BY u.ID,u.Name,a.IsDefault 
) AS tbl 
PIVOT 
(
    SUM(CountPerUserAndDefault) FOR PivotColumn IN([DEFAULT],[NORMAL]) 
) AS p 

Результат:

Name ID DEFAULT NORMAL 
user1 1 1  NULL 
user2 2 NULL 1 
user3 3 1  1 
user4 4 2  NULL 
user5 5 NULL 0 
1

Вы можете использовать CTE в следующем, если вы хотите использовать имена псевдонимов в WHERE пункте:

WITH cte AS (
SELECT AD.User_Id, 
     COUNT(AD.User_Id) AS HowManyAddresses, 
     SUM(
      CASE WHEN 
       AD.IsDefault IS NULL 
       OR 
       AD.IsDefault = 0 
      THEN 
       1 
      ELSE 
       0 
      END 
     ) AS DefaultEmpty, 

     SUM(
      CASE WHEN 
       AD.IsDefault = 1 
      THEN 
       1 
      ELSE 
       0 
      END 
     ) AS DefaultAddress 

FROM dbo.Addresses AS AD 
    JOIN dbo.Users AS U 
    ON U.Id = AD.User_Id 
GROUP BY AD.User_ID 
ORDER BY AD.User_Id 
) 
SELECT * 
FROM cte 
WHERE /* You can use alias names here... */ 
GROUP BY /* You can use alias names here... */ 
HAVING /* You can use alias names here... */ 
0

Поместите это после того, как GroupBy

HAVING SUM (CAST (AD.IsDefault AS INT))> 0

 Смежные вопросы

  • Нет связанных вопросов^_^