【问题标题】:Need a query help需要查询帮助
【发布时间】:2011-07-28 10:16:16
【问题描述】:

需要查询帮助。我有一个表格,其中数据表示如下

userid   TransactionTime           FunctionKey
1018     2011-07-27 09:14:38.000   0
1018     2011-07-27 09:17:11.000   99
1018     2011-07-27 09:38:22.000   0
1018     2011-07-27 10:34:50.000   99

我需要一个查询,它会返回这样的数据集:

userid  Intime                  Outtime
1018    2011-07-27 09:14:38.000 2011-07-27 09:17:11.000
1018    2011-07-27 09:38:22.000 2011-07-27 10:34:50.000 

请帮忙..

【问题讨论】:

  • Funtionkey 为 0 时为 Intime,为 99 时为 Outtime
  • 您需要处理“虚假”数据吗? (同时登录和注销,登录后登录,注销后注销等)
  • 为什么对这个问题投反对票!?!?
  • Ya Dems 应该是这样(登录后登录,注销后注销等)。我不知道为什么我的问题会投反对票:S

标签: sql sql-server-2008 select


【解决方案1】:
declare @T table (userid int, TransactionTime datetime, FunctionKey int)
insert into @T values
(1018,     '2011-07-27 09:14:38.000',   0),
(1018,     '2011-07-27 09:17:11.000',   99),
(1018,     '2011-07-27 09:38:22.000',   0),
(1018,     '2011-07-27 10:34:50.000',   99),
(1019,     '2011-07-27 09:14:38.000',   0),
(1019,     '2011-07-27 09:17:11.000',   0),
(1019,     '2011-07-27 09:38:22.000',   99),
(1020,     '2011-07-27 09:14:38.000',   0),
(1020,     '2011-07-27 09:17:11.000',   99),
(1020,     '2011-07-27 09:38:22.000',   99)

;with cte as
( 
  select userid,
         TransactionTime,
         FunctionKey,
         row_number() over(partition by userid order by TransactionTime) as rn
  from @T
)
select C1.userid,
       C1.TransactionTime as InTime,
       C2.TransactionTime as OutTime
from cte as C1
  left outer join cte as C2
    on C1.userid = C2.userid and
       C1.rn + 1 = C2.rn
where C1.FunctionKey = 0

结果:

userid      InTime                  OutTime
----------- ----------------------- -----------------------
1018        2011-07-27 09:14:38.000 2011-07-27 09:17:11.000
1018        2011-07-27 09:38:22.000 2011-07-27 10:34:50.000
1019        2011-07-27 09:14:38.000 2011-07-27 09:17:11.000
1019        2011-07-27 09:17:11.000 2011-07-27 09:38:22.000
1020        2011-07-27 09:14:38.000 2011-07-27 09:17:11.000

【讨论】:

  • 假设每次注销都会立即登录,并且登录永远不会立即登录。 +1,因为 OP 没有明确说明。
  • 这可以正常工作 Mikael...但是如果连续两行具有相同的 FunctionKey 值怎么办?
  • @Tanvir 更新了我的答案以回答您的问题。对于连续的 0,它将使用第二个 0 作为注销 和 作为登录。它将省略连续 99 之间的时间跨度。
  • @Dems 不确定你的意思。如果第一条记录(对于用户)是 99,则没有匹配的登录名,因此不会包含该记录。此查询使用作为登录的第一条记录并从下一条记录中获取退出时间,无论该记录是登录还是注销。这意味着连续登录被视为隐式注销。应用崩溃时很可能就是这种情况。
  • @Mikael - 我的意思就是你所说的 :) 如果第一条记录是注销,则它不包含在结果中。根据我对此类数据的经验,通常希望包含它,然后推断登录。例如,如果报告是从午夜开始的,并且第一条记录是注销,则假设从午夜开始登录。然后,登录后的登录被视为注销和立即重新登录,注销后的注销被视为注销后立即重新注销。这一切都取决于,我只是指出一个含义:)
【解决方案2】:
WITH
  ordered AS
(
  SELECT
    ROW_NUNBER() OVER (PARTITION BY userid ORDER BY TransactionTime, FunctionKey) item_id,
    *
  FROM
    myTable
)
, logins AS
(
  SELECT * FROM ordered WHERE FunctionKey = 0
)
, logouts AS
(
  SELECT * FROM ordered WHERE FunctionKey = 99
)

SELECT
  COALESCE([logins].userid, [logouts].userid),
  [logins].TransactionTime,
  [logouts].TransactionTime
FROM
  [logins]
FULL OUTER JOIN
  [logouts]
    ON  [logouts].userid      =  [logins].userid
    AND [logouts].item_id     =  [logins].item_id + 1
    AND [logouts].FunctionKey <> [logins].FunctionKey
ORDER BY
  COALESCE([logins].TransactionTime, [logouts].TransactionTime)

或者,这一个通过第一次登录来处理登录序列,通过最后一次注销来处理 loggut 序列。

WITH
  ordered AS
(
  SELECT
    ROW_NUNBER() OVER (PARTITION BY userid ORDER BY TransactionTime, FunctionKey)
    -
    ROW_NUMBER() OVER (PARTITION BY userid, FunctionKey ORDER BY TransactionTime)
    AS group_id,
    *
  FROM
    myTable
)
,
  filtered AS
(
  SELECT
    userid,
    FunctionKey,
    CASE WHEN FunctionKey = 0 THEN MIN(TransactionTime) ELSE MAX(TransactionTime) END AS TransactionTime
  FROM
    ordered
  GROUP BY
    userid,
    FunctionKey,
    group_id
)
,
  sequenced AS
(
  SELECT
   ROW_NUMBER() OVER (PARTITION BY userid ORDER BY TransactionTime, FunctionKey) AS item_id,
   *
  FROM
    filtered
)
, logins AS
(
  SELECT * FROM sequenced WHERE FunctionKey = 0
)
, logouts AS
(
  SELECT * FROM sequenced WHERE FunctionKey = 99
)

SELECT
  COALESCE([logins].userid, [logouts].userid),
  [logins].TransactionTime,
  [logouts].TransactionTime
FROM
  [logins]
FULL OUTER JOIN
  [logouts]
    ON  [logouts].userid      =  [logins].userid
    AND [logouts].item_id     =  [logins].item_id + 1
    AND [logouts].FunctionKey <> [logins].FunctionKey
ORDER BY
  COALESCE([logins].TransactionTime, [logouts].TransactionTime)

【讨论】:

    【解决方案3】:

    将表加入自身,从每个表中获取一个时间戳:

    select
      t1.userid,
      t1.TransactionTime as InTime
      t2.TransactionTime as Outtime
    from mytable t1
    join mytable t2 on t2.userid = t1.userid and t2.FunctionKey = 99
    where t1.FunctionKey = 0;
    

    【讨论】:

    • 这会将记录 1 匹配到记录 2 和 4,记录 3 也会匹配到记录 2 和 4。
    猜你喜欢
    • 2011-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-04
    • 2016-07-26
    • 2018-04-06
    相关资源
    最近更新 更多