MySql和变量排除结果集

时间:2012-04-26 15:24:00

标签: mysql variables

我对变量如何在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不应该保留各行的变量吗?

问候。

2 个答案:

答案 0 :(得分: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)
)

答案 1 :(得分:0)

从另一个示例及其评论中,我会以这种方式处理您的查询。如果存在任何“C = 1”值并且存储到CCnt字段中,则预先限定第一个查询。如果未找到,则强制CCnt值为NULL。第二,对“B”栏做同样的事。由于它们中的每一个都具有1的限制,因此只要它可以分别找到C = 1或B = 1的条目就应该快。如果不是,它们的值为NULL。为什么这样?查询在每次运行查询时完成,并且答案完成。它不必重复执行查询,因为当用作子查询时可以是KILLER性能。将GUARANTEE作为单行进行不带分组的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,那么 YT.C = 1就是你需要的全部......以及你不关心的其他“OR”条件,记录即将出现。

现在,假设没有C = 1的条目。我们知道“CCnt”值为NULL,因此它将进入第一个“OR”条件并针对“B”进行测试... B具体= 1 AND CCnt IS NULL ...所以,如果有一个“C = 2”(3,4或任何其他值)的条目,我们不希望它。我们只想要B = 1 AND C = NULL ...

如果C和B失败,那么我们就会进入“A”测试。同样地,A = 1 AND B为空且C为NULL,原因与上述B相同。

对于小桌子,您可能没有注意到Shedal的答案有任何显着的性能差异。然而,随着你的桌子的增长,它可能会受到巨大打击。