0

我有一个查询来检查数据库以查看客户是否一天访问过多次。如果他们有,它会计算访问次数,然后告诉我他们访问的时间。问题是它把“Tickets.lcustomerid”扔进了 group by 子句,导致我错过了 5 条记录(没有条形码的客户)。如何更改以下查询以从 group by 子句中删除“tickets.lcustomerid”...如果删除它,我收到错误消息,告诉我“Tickets.lCustomerID”不是有效选择,因为它不是聚合的一部分或groupby 子句。

有效的查询:

SELECT        Customers.sBarcode, CAST(FLOOR(CAST(Tickets.dtCreated AS FLOAT)) AS DATETIME) AS dtCreatedDate, COUNT(Customers.sBarcode) AS [Number of Scans], 
                         MAX(Customers.sLastName) AS LastName
FROM            Tickets INNER JOIN
                         Customers ON Tickets.lCustomerID = Customers.lCustomerID
WHERE        (Tickets.dtCreated BETWEEN @startdate AND @enddate) AND (Tickets.dblTotal <= 0)
GROUP BY Customers.sBarcode, CAST(FLOOR(CAST(Tickets.dtCreated AS FLOAT)) AS DATETIME)
HAVING        (COUNT(*) > 1)
ORDER BY dtCreatedDate

输出是:

sBarcode   dtcreated Date      Number of Scans  slastname    
1234     1/4/2013 12:00:00 AM         2          Jimbo         
         1/5/2013 12:00:00 AM         3          Jimbo2       
1578     1/6/2013 12:00:00 AM         3          Jimbo3        

我当前的带有子查询的查询

SELECT customers.sbarcode, 
       Max(customers.slastname)                                  AS LastName, 
       Cast(Floor(Cast(tickets.dtcreated AS FLOAT)) AS DATETIME) AS 
       dtCreatedDate, 
       Count(customers.sbarcode)                                 AS 
       [Number of Scans], 
       Stuff ((SELECT ', ' 
                      + RIGHT(CONVERT(VARCHAR, dtcreated, 100), 7) AS [text()] 
               FROM   tickets AS sub 
               WHERE  ( lcustomerid = tickets.lcustomerid ) 
                      AND ( dtcreated BETWEEN Cast(Floor(Cast(tickets.dtcreated 
                                                              AS 
                                                              FLOAT)) AS 
                                                   DATETIME 
                                              ) 
                                              AND 
Cast(Floor(Cast(tickets.dtcreated 
AS FLOAT 
)) AS 
DATETIME 
) 
+ '23:59:59' ) 
AND ( dbltotal <= '0' ) 
FOR xml path('')), 1, 1, '')                      AS [Times Scanned] 
FROM   tickets 
       INNER JOIN customers 
               ON tickets.lcustomerid = customers.lcustomerid 
WHERE  ( tickets.dtcreated BETWEEN @startdate AND @enddate ) 
       AND ( tickets.dbltotal <= 0 ) 
GROUP  BY customers.sbarcode, 
          Cast(Floor(Cast(tickets.dtcreated AS FLOAT)) AS DATETIME), 
          tickets.lcustomerid 
HAVING ( Count(*) > 1 ) 
ORDER  BY dtcreateddate 

当前输出(注意没有条形码的记录丢失)是:

sBarcode   dtcreated Date      Number of Scans  slastname    Times Scanned
1234     1/4/2013 12:00:00 AM         2          Jimbo         12:00PM, 1:00PM
1578     1/6/2013 12:00:00 AM         3          Jimbo3        03:05PM, 1:34PM
4

2 回答 2

1

更新:根据我们的“聊天”,似乎 customerid 不是唯一字段,但条形码是,即使客户 ID 是主键。

因此,为了不在子查询中 GROUP BY 客户 ID,您需要加入其中的第二个客户表,以便实际加入条形码。

试试这个:

SELECT customers.sbarcode, 
       Max(customers.slastname)                                  AS LastName, 
       Cast(Floor(Cast(tickets.dtcreated AS FLOAT)) AS DATETIME) AS 
       dtCreatedDate, 
       Count(customers.sbarcode)                                 AS 
       [Number of Scans], 
       Stuff ((SELECT ', ' 
                      + RIGHT(CONVERT(VARCHAR, dtcreated, 100), 7) AS [text()] 
               FROM   tickets AS subticket
               inner join
               customers as subcustomers
               on
               subcustomers.lcustomerid = subticket.lcustomerid
               WHERE  ( subcustomers.sbarcode = customers.sbarcode ) 
                      AND ( subticket.dtcreated BETWEEN Cast(Floor(Cast(tickets.dtcreated 
                                                              AS 
                                                              FLOAT)) AS 
                                                   DATETIME 
                                              ) 
                                              AND 
Cast(Floor(Cast(tickets.dtcreated 
AS FLOAT 
)) AS 
DATETIME 
) 
+ '23:59:59' ) 
AND ( dbltotal <= '0' ) 
FOR xml path('')), 1, 1, '')                      AS [Times Scanned] 
FROM   tickets 
       INNER JOIN customers 
               ON tickets.lcustomerid = customers.lcustomerid 
WHERE  ( tickets.dtcreated BETWEEN @startdate AND @enddate ) 
       AND ( tickets.dbltotal <= 0 ) 
GROUP  BY customers.sbarcode, 
          Cast(Floor(Cast(tickets.dtcreated AS FLOAT)) AS DATETIME)
HAVING ( Count(*) > 1 ) 
ORDER  BY dtcreateddate 
于 2013-02-07T15:20:59.853 回答
1

我无法直接解决您的问题,因为我不了解您的数据模型或您试图通过此查询完成的工作。但是,我可以就如何自己解决问题给您一些建议。

首先,您是否准确了解您要完成的工作以及表格如何组合在一起?如果是,请继续下一步,如果不是,请先了解此知识,没有此了解,您将无法进行复杂的查询。

接下来,分步分解您要完成的工作,并确保在进行其余部分之前已涵盖每个步骤。因此,在您的情况下,您似乎缺少一些客户。从一个新查询开始(我很确定这个查询不止一个问题)。所以从 join 和 where 子句开始。

我怀疑您可能需要从客户开始并左连接到票(这会将 where 条件移动到左连接,因为它们在票上)。这将为您提供所有客户,无论他们是否有票。如果这不是您想要的,则使用 jon 和 where 子句(并在您尝试解决问题时使用 select *),直到您返回所需的确切客户记录集。在此阶段使用 select * 的原因是查看数据中的哪些内容可能导致您遇到的问题。这可能会告诉你如何修复。

通常我从连接开始,然后一次添加一个 where 子句,直到我知道我得到了正确的初始记录集。如果您有多个联接,请一次执行一次,以了解您何时突然开始拥有比预期更多或更少的记录。

然后进入更复杂的部分。一次添加一个并检查结果。如果您突然从 10 条记录变为 5 或 15 条,那么您可能遇到了问题。当您一次一步工作并遇到问题时,您会确切地知道导致问题的原因,从而更容易找到和修复。

Group BY 很重要,要彻底理解。您必须拥有 group by 中的每个非聚合字段,否则它将不起作用。把它想象成像万有引力定律一样的定律。这不是你可以改变的。但是,它可以通过使用派生表或 CTE 来解决。如果你不知道它们是什么,请仔细阅读它们,当你接触复杂的东西时,它们是非常有用的技术,你应该彻底理解它们。我怀疑您将需要在这里使用派生表方法来仅对您需要的内容进行分组,然后将该派生表加入到其余查询中以获取 ontehr 字段。我将展示一个简单的例子:

select 
      t1.table1id
    , t1.field1
    , t1.field2
    , a.field3
    , a.MostRecentDate
From table1 t1
JOIN
    (select t1.table1id, t2.field3, max (datefield) as MostRecentDate 
    from table1 t1
    JOin Table2 t2 on t1.table1id = t2.table1id
    Where t2.field4 = 'test'
    group by t1.table1id,t2.field3) a
    ON a.table1id = t1.table1id

希望这种方法可以帮助您解决这个问题。

于 2013-02-07T15:44:51.217 回答