簡體   English   中英

基於過濾條件的T-SQL查詢列

[英]T-SQL Query Column based on filtered condition

我可以用 Python(或任何其他語言)很容易地做到這一點,但我想看看這是否可以用純 T-sql

我有兩個表:

表 A 的每一行都有一堆通用數據和時間戳

+------+------+------+-----------+
| Col1 | Col2 | Col3 | Timestamp |
+------+------+------+-----------+
| A    | B    | C    | 17:00     |
| D    | E    | F    | 18:00     |
| G    | H    | I    | 23:00     |
+------+------+------+-----------+

表 B 被視為元數據

+-------+-----------+
| RunNo | Timestamp |
+-------+-----------+
|     1 | 16:50     |
|     2 | 17:30     |
|     3 | 18:00     |
|     4 | 19:00     |
+-------+-----------+

所以一般數據被引用到“RunNo”。 表 B 中的時間戳正好是在數據庫中創建“運行”的時間。 您可以通過比較時間戳將常規數據與其正確的運行編號進行匹配。 例如,表 A 中第一行的時間戳為 17:00,大於 16:50 且小於 17:30,因此顯然該行屬於 RunNo 1。如何執行此查詢,以便生成的表是

+------+------+------+-----------+-------+
| Col1 | Col2 | Col3 | Timestamp | RunNo |
+------+------+------+-----------+-------+
| A    | B    | C    | 17:00     |     1 |
| D    | E    | F    | 18:00     |     2 |
| G    | H    | I    | 23:00     |     4 |
+------+------+------+-----------+-------+

我雖然在這里使用 CASE 可能會有所幫助,但我不知道如何把它放在一起

SELECT a.*,
       CASE WHEN a.TIMESTAMP < b.TIMESAMP AND a.TIMESTAMP > b.TIMSTAMP then b.RunNo END AS RunNo
FROM A as a, B as b

任何幫助將不勝感激。

CASE允許您根據條件返回不同的值(即列或表達式)。 這不是你這里的什么。 您想要連接表並根據條件過濾匹配的行。

我已經用ts替換了名稱Timestamp ,因為即使逃脫了,我在SQL Fiddle上也遇到了困難。 它是一個保留關鍵字。

SELECT A.Col1, A.Col2, A.Col3, A.ts, MAX(B.RunNo) AS RunNo
FROM
    A
    INNER JOIN B
        ON A.ts > B.ts
GROUP BY A.Col1, A.Col2, A.Col3, A.ts       

使用A.ts > B.ts這會為第二個條目返回RunNo 2。 如果A.ts >= B.ts這將返回第二個條目的RunNo 3。

http://sqlfiddle.com/#!18/9dd143/6/0

with TableA as (
    Select [Col1] = 'A',[Col2] = 'B',[Col3] = 'C',[Timestamp] = '17:00'
    Union all Select [Col1] = 'D',[Col2] = 'E',[Col3] = 'F',[Timestamp] = '18:00'
    Union all Select [Col1] = 'G',[Col2] = 'H',[Col3] = 'I',[Timestamp] = '23:00'
)
, TableB as (
    Select [RunNo] = '1',[Timestamp] = '16:50'
    Union all Select [RunNo] = '2',[Timestamp] = '17:30'
    Union all Select [RunNo] = '3',[Timestamp] = '18:00'
    Union all Select [RunNo] = '4',[Timestamp] = '19:00'
)
, TableBWithRowNumber as (
    select b.RunNo, ROW_NUMBER() over (order by b.timestamp asc) as number, cast(b.Timestamp as time) as timestamp
    from TableB b
)
, TableBWithNextRun as (
    select b1.RunNo, startTime = b1.timestamp , endTime = b2.timestamp
    from TableBWithRowNumber b1
    left join TableBWithRowNumber b2 on b1.number + 1= b2.number
)
select * 
from TableA a
inner join TableBWithNextRun B 
    on a.Timestamp >= b.startTime and (a.Timestamp < b.endTime or b.endTime is null)

這會將您的時間戳轉換為time 我不確定你的內部數據類型是什么。

這輸出以下

Col1    Col2    Col3    Timestamp   RunNo   startTime           endTime
A       B       C       17:00       1       16:50:00.0000000    17:30:00.0000000
D       E       F       18:00       3       18:00:00.0000000    19:00:00.0000000
G       H       I       23:00       4       19:00:00.0000000    NULL

您可以使用滯后函數獲取列的先驗值,然后加入。

WITH Runs AS
(
  SELECT
    RunNo, 
    COALESCE(LAG(TIMESTAMP),'00:00')) AS START_TS,
    TIMESTAMP AS END_TS
  FROM TableB
  ORDER BY RunNo ASC
)
SELECT B.RunNo, A.*
FROM TableA A
JOIN Runs B ON A.Timestamp >= B.Start_TS AND A.Timestamp < B.End_Ts

這應該比更大數據集上的任何 group by 解決方案都快。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM