SQL - TOP 1和MIN不起作用但MAX工作

时间:2014-05-26 14:37:22

标签: sql max min

我这里有一个奇怪的错误。

我正在尝试将以下查询的结果限制为仅一行/结果:

SELECT userEmail
    FROM [LunchUsersAvailable]
    WHERE LunchGroupsID = '301' AND availableDate = '2015-01-01' AND userEmail != 'userEmail@company.com' EXCEPT
    (
        SELECT DISTINCT (COALESCE([user1], [user2])) AS matchedEmail
        FROM
        (
                SELECT [user1], [user2]
                FROM [LunchMatched]
            UNION ALL
                SELECT [user2], [user1]
                FROM [LunchMatched]
        ) AS tmp
        WHERE (user1 = 'userEmail@company.com' OR user2 = 'userEmail@company.com')
    )

输出:

test2@company.com

test3@company.com

test4@company.com


我尝试使用 TOP 1 。没工作。根本没有结果。

SELECT TOP 1 userEmail
    FROM [LunchUsersAvailable]
    WHERE LunchGroupsID = '301' AND availableDate = '2015-01-01' AND userEmail != 'userEmail@company.com' EXCEPT
    (
        SELECT DISTINCT (COALESCE([user1], [user2])) AS matchedEmail
        FROM
        (
                SELECT [user1], [user2]
                FROM [LunchMatched]
            UNION ALL
                SELECT [user2], [user1]
                FROM [LunchMatched]
        ) AS tmp
        WHERE (user1 = 'userEmail@company.com' OR user2 = 'userEmail@company.com')
    )

我也用 MIN()进行了测试。没有结果。

SELECT MIN (userEmail)  as email
    FROM [LunchUsersAvailable]
    WHERE LunchGroupsID = '301' AND availableDate = '2015-01-01' AND userEmail != 'userEmail@company.com' EXCEPT
    (
        SELECT DISTINCT (COALESCE([user1], [user2])) AS matchedEmail
        FROM
        (
                SELECT [user1], [user2]
                FROM [LunchMatched]
            UNION ALL
                SELECT [user2], [user1]
                FROM [LunchMatched]
        ) AS tmp
        WHERE (user1 = 'userEmail@company.com' OR user2 = 'userEmail@company.com')
    )

我用 MAX()测试以防万一。 有效!

SELECT MAX (userEmail)  as email
    FROM [LunchUsersAvailable]
    WHERE LunchGroupsID = '301' AND availableDate = '2015-01-01' AND userEmail != 'userEmail@company.com' EXCEPT
    (
        SELECT DISTINCT (COALESCE([user1], [user2])) AS matchedEmail
        FROM
        (
                SELECT [user1], [user2]
                FROM [LunchMatched]
            UNION ALL
                SELECT [user2], [user1]
                FROM [LunchMatched]
        ) AS tmp
        WHERE (user1 = 'userEmail@company.com' OR user2 = 'userEmail@company.com')
    )

输出:

test4@company.com


总之,我的问题是:如何获得 test2@company.com


更新测试更新 我做了两个不同的测试。一个工作,另一个不工作。我会详细展示每一个。首先,测试一切正常:

我想分别解释每个SELECT和每个部分的结果:

-- this outter SELECT lists all available users who are available
SELECT userEmail FROM [LunchUsersAvailable]
WHERE LunchGroupsID = '301' AND availableDate = '2015-01-01' AND userEmail != 'userEmail@company.com'

输出:

test1@company.com

test2@company.com

test3@company.com

test4@company.com

(4行(s)受影响)


-- this inner SELECT lists all the users who has been paired with userEmail@company.com before
SELECT DISTINCT (COALESCE([user1], [user2])) AS matchedEmail
FROM
(
        SELECT [user1], [user2]
        FROM [LunchMatched]
    UNION ALL
        SELECT [user2], [user1]
        FROM [LunchMatched]
) AS tmp
WHERE (user1 = 'userEmail@company.com' OR user2 = 'userEmail@company.com')

输出:

userEmail@company.com

test2@company.com

(2行(s)受影响)


运行完整代码,没有 TOP 1,MIN()或MAX():

test1@company.com

test3@company.com

test4@company.com

(3行受影响)


到目前为止所有正确的。现在我只需要获得 test1@company.com 部分,所以我改变了代码的第一行     SELECT userEmail FROM [LunchUsersAvailable] 至     SELECT TOP 1 userEmail FROM [LunchUsersAvailable]

结果是:

test1@company.com

(1行受影响)


绝对正常。

但现在,如果 userEmail@company.com 先前已与 test1@company.com而非test2@company.com 匹配([LunchMatched]表)结果不同。

INNER,OUTTER和FULL代码(没有TOP 1,MIN或MAX)的工作方式与上面说明的相同,很好。

但是,如果我更改代码的第一行     SELECT userEmail FROM [LunchUsersAvailable] 至     SELECT TOP 1 userEmail FROM [LunchUsersAvailable]

结果是 null ,而不是正确的结果: test2@company.com

(1行受影响)

3 个答案:

答案 0 :(得分:1)

这表明userEmail接受多个值,其中一个是空字符串('' - 而不是NULL)。

userEmail返回的第一行具有此空值。 min()会抓住它。 max()没有。

选中userEmail <> ''或只使用max()

如果您想要min(),您还可以使用带有case的条件聚合:

select min(case when userEmail > '' then userEmail end)

编辑:

我看到了问题。 top 1min()max()引用except之前的第一个查询。我错过了except,因为它在行尾滚动了。 except的作用类似于union,将查询连接在一起。它不是where子句的一部分。

答案 1 :(得分:0)

我明白了! TOP 1或MIN正在处理之前 EXCEPT,这意味着它将首先从可用用户结果获得TOP 1,并且只有他们应用EXCEPTION。

解决方案:获取可用用户的完整列表,运行例外,然后获取TOP 1

 SELECT TOP 1 useremail FROM (
    SELECT userEmail
    FROM [LunchUsersAvailable]
    WHERE LunchGroupsID = '301' AND availableDate = '2015-01-01' AND userEmail != 'userEmail@company.com' EXCEPT        -- from a specific cafeteria and date, EXCEPT
    (
        SELECT DISTINCT (COALESCE([user1], [user2])) AS matchedEmail                                                                        -- select all matched users in one column
        FROM
        (
                SELECT [user1], [user2]
                FROM [LunchMatched]
            UNION ALL
                SELECT [user2], [user1]
                FROM [LunchMatched]
        ) AS tmp
        WHERE (user1 = 'userEmail@company.com' OR user2 = 'userEmail@company.com')                                                  -- who has been previously matched with the user who is registering now
    )
) as tmp

答案 2 :(得分:0)

这不是答案。这只是为了说明如何简化原始查询。以下是三种可能性:

SELECT userEmail
FROM LunchUsersAvailable
WHERE LunchGroupsID = '301' 
AND availableDate = '2015-01-01' 
AND userEmail != 'userEmail@company.com' 
EXCEPT
(
  SELECT user1
  FROM LunchMatched 
  WHERE user2 = 'userEmail@company.com'
  UNION ALL
  SELECT user2
  FROM LunchMatched 
  WHERE user1 = 'userEmail@company.com'
);

或者:

SELECT userEmail
FROM LunchUsersAvailable
WHERE LunchGroupsID = '301' 
AND availableDate = '2015-01-01' 
AND userEmail != 'userEmail@company.com' 
AND userEmail NOT IN
(
  SELECT user1
  FROM LunchMatched 
  WHERE user2 = 'userEmail@company.com'
)
AND userEmail NOT IN
(
  SELECT user2
  FROM LunchMatched 
  WHERE user1 = 'userEmail@company.com'
);

或者:

SELECT userEmail
FROM LunchUsersAvailable
WHERE LunchGroupsID = '301' 
AND availableDate = '2015-01-01' 
AND userEmail != 'userEmail@company.com' 
AND NOT EXISTS
(
  SELECT *
  FROM LunchMatched 
  WHERE LunchUsersAvailable.userEmail IN (LunchMatched.user1, LunchMatched.user2)
  AND 'userEmail@company.com' IN (LunchMatched.user1, LunchMatched.user2)
);

在第二个和第三个查询中,可以轻松地将userEmail替换为MIN(userEmail)。在第一个中,这将通过SELECT MIN(userEmail) FROM (first query here)完成。