2012-04-26 56 views
0

我有疑問如何在mysql中使用變量。正如我在他們的網頁上看到的,設置一個變量將會在下一行顯示出來。MySql和要排除結果集的變量

我的表像:

A  B  C  N 
1 NULL NULL 4 
1 NULL NULL 4 
1  1  NULL 4 
1  1  NULL 4 
1  1  1  4 
1  1  1  4 

我要的是隻與C = 1返回行。如果沒有行,則返回B = 1 and C is NULL,如果沒有行A = 1 and B is NULL and C is NULL

我的想法是:

select N as number, 
     @var_c := case when (C = 1) then 1 else -1 end as myc, 
     @var_b := case when (@var_c < 0 and B = 1) then 1 else -1 end as myB, 
     @var_c := case when (@var_a < 0 and var_b < 0 and C = 1) then 1 else -1 end as myC 

from (select @var_a := -1) r_a, 
    (select @var_b := -1) r_b, 
    (select @var_c := -1) r_c, 
    (select A, B, C, N from my_table order by A desc, B desc, C desc) rows 

應該(我想)返回

number  myA myB myC 
    4   -1  -1 1 
    4   -1  -1 1 
    4   -1  -1 -1 
    4   -1  -1 -1 
    4   -1  -1 -1 
    4   -1  -1 -1 

有了這個和having myA > 0 or myB > 0 or myC > 0會工作。

但它返回

number myA  myB myC 
    4   1  -1 -1 
    4   1  -1 -1 
    4   -1  -1 1 
    4   -1  -1 1 
    4   -1  1 -1 
    4   -1  1 -1 

不應該保留的Mysql橫跨行的瓦爾?

問候。

+0

實際上,我在整個S/O的許多查詢中都使用了sqlvars。基礎是,你可以在一個單獨的(你選擇AtVar1:= 0,AtVar2:= 0,AtVar3:='test',AtEtc:='more')sqlvars中執行from子句。然後,如果您希望調整變量,則可以按照原樣進行操作,並且新值可用於查詢中的下一行。但是,您能否提供一些真實的樣本數據,包括您所期望的結果與預期結果。儘管我明白你的標準。 – DRapp 2012-04-28 00:23:45

+0

@DRapp我真的給了我的表的示例。而我想要的。感謝您的評論 – ssedano 2012-04-28 20:08:07

+0

好吧,然後讓我問這個。如果甚至有一個C = 1的SINGLE行,你是否永遠不想要任何A或B限定符(一個查詢)?或者在每行的基礎上,每個都被確定爲包含或不包含NULL值。這將允許許多行,但包括符合C = 1或C = NULL且B = 1或C = NULL且B = NULL且A = 1的ALL。您的結果集可以包含全部3種(這些類型的記錄)。你想要哪個版本。 – DRapp 2012-04-28 20:44:18

回答

1

首先,不要使用這樣的變量。您不應該期望您可以在FROM子句中設置變量,然後訪問SELECT子句中的值。這不是變量的工作原理。通常你只能在查詢中的一個地方使用一個變量,否則你可能會得到不確定的結果。

其次,爲什麼不只是發出三個不同的查詢?首先爲A = 1 and B is NULL and C is NULL,如果它沒有返回任何行,則發出第二個條件集的查詢。等等。

如果你最終要發佈只是一個單一的查詢,你可以試試這個:

SELECT N as number 
FROM my_table 
WHERE IF(EXISTS (SELECT A FROM my_table WHERE A = 1 and B is NULL and C is NULL), 
    A = 1 and B is NULL and C is NULL, 
    IF(EXISTS (SELECT A FROM my_table WHERE B = 1 and C is NULL), B = 1 and C is NULL, C = 1)) 

但它很可能殺性能。所以最好只使用三個查詢而不是一個。

UPD:還有一個(但類似的)做法:

SELECT N as number 
FROM my_table 
WHERE (
    A = 1 
    AND B is NULL 
    AND C is NULL 
) OR (
    B = 1 
    AND C is NULL 
    AND NOT EXISTS (SELECT A FROM my_table WHERE A = 1 and B is NULL and C is NULL) 
) OR (
    C = 1 
    AND NOT EXISTS (SELECT A FROM my_table WHERE A = 1 and B is NULL and C is NULL) 
    AND NOT EXISTS (SELECT A FROM my_table WHERE B = 1 and C is NULL) 
) 
+0

要求在一個查詢中完成。會嘗試你的!告訴你什麼。感謝您的答覆。 – ssedano 2012-04-26 15:38:54

+0

@ssedano在這種情況下,請讓我知道我寫的作品是否適合作品 – 2012-04-26 15:40:53

+0

作品,謝謝。我已經爲你+1了。但我想等一下,如果有人澄清我的變數問題。然後比較性能。如果您的答案是我選擇實施的答案,我會將其標記爲有效。如果沒有更多的答案給出,那麼你的要做到這一點。 – ssedano 2012-04-26 16:00:19

0

從其他樣品,它的意見,我會接近你的查詢這個樣子。第一個預先限定是否存在任何「C = 1」值並存儲到CCnt字段的查詢。如果沒有找到,強制CCnt值爲NULL。第二,對「B」欄執行相同的操作。由於每一個都有1的限制,只要它能分別找到C = 1或B = 1的條目就應該快。如果不是,它們的值是NULL。爲什麼這樣做?每查詢一次,查詢就完成一次,答案就完成了。在用作子查詢時,不必重複執行查詢,因爲可以將KILLER性能反覆執行。做一個沒有分組的count()會保證爲單行,所以你不會有任何可能導致重複的笛卡爾結果。

現在這個搶先查詢已完成,現在添加到您的主表。此時,「HasCEntry.CCnt」值將爲1或NULL。 「HasBEntry.CCnt」值將爲1或NULL。

select 
     YT.* 
    from 
     (select IF(count(*) > 0, 1, NULL) as CCnt 
      from YourTable 
      where C = 1 
      limit 1) HasCEntry, 
     (select IF(count(*) > 0, 1, NULL) as BCnt 
      from YourTable 
      where B = 1 
      limit 1) HasBEntry, 
     YourTable YT 
    where 
      YT.C = 1 
     OR (YT.B = 1 AND HasCEntry.CCnt IS NULL) 
     OR (YT.A = 1 AND HasBEntry.BCnt IS NULL AND HasCEntry.CCnt IS NULL) 

現在,遵循WHERE子句。如果在C = 1的情況下甚至有1條記錄,那麼您所需要的就是所有您需要的和完成的......以及您不關心的其他「或」條件,記錄即將到來。我們知道「CCnt」值爲NULL,因此會進入第一個「OR」條件並針對「B」進行測試... B具體= 1並且CCnt IS NULL ...因此,如果有「C = 2」(3,4或任何其他值)的條目,我們不需要它。我們只希望B = 1和C = NULL ...

如果C和B失敗,那麼我們就會進入「A」測試。同樣,由於與上述B相同的原因,A = 1 AND B爲空且C爲NULL。

對於一張小桌子,您可能沒有注意到Shedal的答案有任何顯着的性能差異。然而,隨着桌子的增長,它會變得非常受歡迎。