2015-08-03 61 views
0

我使用的是Postgres 9.4,並希望做這樣的事情:SQL大於IN

movement_id|counter|standardized_output 
--------------------------------------- 
1   |  3|     10 
1   |  3|     12 
1   |  5|     10 
2   |  4|     5 

我有以下查詢:

SELECT movement_id, counter, MAX(standardized_output) AS standardized_output 
FROM "outputs" 
WHERE "outputs"."user_id" = 1 AND "outputs"."movement_id" IN (1,2) AND (counter in (1,3,5)) 
GROUP BY movement_id, counter 

這給了我:

movement_id|counter|standardized_output 
--------------------------------------- 
1   |  3|     12 
1   |  5|     10 

但是我想找到的是MAX(standard_output)是counter >= (1,3,5)。所以下面的結果:

movement_id|counter|standardized_output 
--------------------------------------- 
1   |  1|     12 (MAX value where movement_id is 1 and counter is >=1) 
1   |  3|     12 (MAX value where movement_id is 1 and counter is >=3) 
1   |  5|     10 (MAX value where movement_id is 1 and counter is >=5) 
2   |  1|     5 (MAX value where movement_id is 2 and counter is >=1) 
2   |  3|     5 (MAX value where movement_id is 2 and counter is >=3) 
2   |  5|    null (MAX value where movement_id is 2 and counter is >=5) 

(小編輯:movement_id是IN,不等於)

+0

您是否想要standard_output超過提供的數字中的每個值或至少多個值? – ogres

+0

什麼是你的表中的數據? – tharif

+1

因此,即使沒有'movement_id'和'counter'的相應組合,您每個movement_id都需要三行(因爲您的IN列表包含三個計數器值)(您的樣本數據不會顯示例如2,1的值) –

回答

0

正如你想要的行沒有任何值的結果,你首先需要創建一個由應該在那裏的行組成的集合,在這個例子中是{movement_id} X {1,3,5}的笛卡爾積。爲此,我們可以使用交叉連接和表值構造函數,然後使用左連接和子查詢來獲取最大值。

我相信這個查詢可以改進,但它應該工作。

select 
    all_values.movement_id, 
    all_values.num, 
    ( 
     select max(standardized_output) 
     from outputs 
     where counter >= all_values.num 
     and movement_id = all_values.movement_id 
    ) as standardized_output 
from (
    select movement_id, t.num 
    from outputs 
    cross join (values (1), (3), (5)) as t(num) 
    where "movement_id" in (1 ,2) 
-- and "outputs"."user_id" = 1 --this was missing in your sample so I left it commented out. 
) all_values 
left join outputs o on all_values.movement_id = o.movement_id 
        and (counter in (all_values.num)) 
group by all_values.movement_id, all_values.num 
order by all_values.movement_id, all_values.num; 

Sample SQL Fiddle

鑑於你的樣本數據,從上面的查詢結果是:

| movement_id | num | standardized_output | 
|-------------|-----|---------------------| 
|   1 | 1 |     12 | 
|   1 | 3 |     12 | 
|   1 | 5 |     10 | 
|   2 | 1 |     5 | 
|   2 | 3 |     5 | 
|   2 | 5 |    (null) | 

編輯:

select 
    o1.movement_id, 
    t.num as counter, 
    max(o2.standardized_output) as standardized_output 
from outputs o1 cross join (values (1), (3), (5)) as t(num) 
left join outputs o2 on o1.movement_id = o2.movement_id and t.num <= o2.counter 
where o1.movement_id in (1,2) 
group by o1.movement_id, t.num 
order by o1.movement_id, t.num; 

:相同的結果可使用此查詢來實現Sample fiddle

+0

奇妙的是,這個作品!如果不是用null標準化輸出返回一行,我們是不會返回任何東西的,那麼效率會提高嗎? –

+0

@本史密斯我不認爲這很重要;至少不會像移動_id和計數器值的集合那麼長。創建笛卡爾產品並不昂貴 - 代價高昂的部分很可能是相關的子查詢(我認爲這可能會改寫爲連接)。 – jpw

+0

@BenSmith我添加了第二個查詢也應該工作,可能表現更好(加上它有點短)。 – jpw

0

你也許可以把CASE聲明櫃檯上的場?

CASE WHEN counter >= 5 THEN 5 
WHEN counter >=3 THEN 3 
WHEN counter >=1 THEN 1 
ELSE 0 END 

然後將其添加到select和group by子句中。

SELECT movement_id, 
    (CASE WHEN counter >= 5 THEN 5 
     WHEN counter >=3 THEN 3 
     WHEN counter >=1 THEN 1 
     ELSE 0 END) as new_counter, 
    MAX(standardized_output) AS standardized_output 
FROM "outputs" 
WHERE "outputs"."user_id" = 1 AND "outputs"."movement_id" = 1 
GROUP BY movement_id, 
    (CASE WHEN counter >= 5 THEN 5 
     WHEN counter >=3 THEN 3 
     WHEN counter >=1 THEN 1 
     ELSE 0 END) 
+0

這對我的文章中的示例數據沒有產生任何計數= 1的條目 –

0

我正要張貼在線路KEZ什麼做(利用該case聲明的)東西,但有點不同。

我不確定在這種情況下您需要哪些條件,我不知道計數器> =(1,3,5)是否可以轉換爲計數器> = 5?在下面的示例中,我正在考慮計數器> =(1,3,5)意味着計數器> = 5(問題是如何在這裏理解分號 - 如果要將它們轉換爲AND或OR,因此counter> =(1,3,5)與counter> = 5相同,但是如果分號應理解爲OR,則表示計數器值爲2或4您感興趣)

無論如何,無論您不希望在最大功能中考慮您的標準化輸出的情況,都將它們包括在案例條件中並使它們的計數器返回零,因此它不會影響您的最大值(如果需要,也不會影響負數)

SELECT 
     movement_id, 
     counter, 
     MAX(CASE WHEN COUNTER < 1 THEN 0 ELSE COUNTER END) AS standardized_output 
    FROM outputs 
WHERE 
    outputs.user_id = 1 
    AND outputs.movement_id = 1 
    AND counter in (1, 3, 5) 
GROUP BY movement_id, counter 
0

您可以使用CASE statem耳鼻喉科與MAX()功能像

SELECT movement_id, 
counter, 
MAX(CASE WHEN movement_id = 1 and counter >= 1 THEN standardized_output 
WHEN movement_id = 1 and counter >= 3 THEN standardized_output 
WHEN movement_id = 1 and counter >= 5 THEN standardized_output 
WHEN movement_id = 2 and counter >= 1 THEN standardized_output 
WHEN movement_id = 2 and counter >= 3 THEN standardized_output 
WHEN movement_id = 2 and counter >= 5 THEN standardized_output 
ELSE NULL END) AS standardized_output 
FROM "outputs" 
WHERE "outputs"."user_id" = 1 
AND "outputs"."movement_id" = 1 
AND (counter in (1,3,5)) 
GROUP BY movement_id, counter; 
+0

對不起,我澄清了我的問題,我需要能夠對任意數量的movement_id 。 –

0

除非我完全誤解你想要做什麼,你應該能夠聯接到處理這個問題:

SELECT o.movement_id, 
    o.counter_id, 
    MAX(oagg.standardized_output) AS standardized_output 
FROM outputs o 
LEFT JOIN outputs oagg 
    ON o.user_id  = oagg.user_id 
    AND o.other_primary = oagg.other_primary 
    AND o.movement_id = oagg.movement_id 
    AND o.counter_id <= oagg.counter_id 
WHERE o.user_id = 1; 

如果你想明確counter_id不存在,您需要以某種方式創建它們。我可能會加入一張理貨表,但我不確定我完全理解你要找的東西。

+0

對不起,我澄清了我的問題。我需要在單個查詢中爲多個movement_id執行此操作,您的聯接解決方案是否可以適用於此?謝謝。 –

+0

I還有一個錯誤,說'列「o.movement_id」必須出現在GROUP BY子句中或用於聚合函數中# –

+0

@BenSmith哦,對了,我忘了GROUP BY。我也會看看更新。 –