我需要相当于这个Count with Case for Firebird 3数据库

时间:2018-03-27 19:54:35

标签: sqlite count case firebird

对于Firebird 3数据库,我需要相当于此Count with Case。我尝试时遇到错误:

SQL error code = -104.
Invalid usage of boolean expression.

我刚刚介绍了Case命令,我似乎无法自行修改它。我设法让它与SQLite一起使用。

目的是进行AND操作,Where不能做AND,因为关键字在行中。

SELECT Count((CASE WHEN keywords.keyword LIKE '%purchased%'
              THEN 1 END) AND
             (CASE WHEN keywords.keyword LIKE '%item%'
              THEN 1 END)) AS TRows
FROM products
     LEFT OUTER JOIN keywords_products ON
       products.product_rec_id = keywords_products.product_rec_id
     LEFT OUTER JOIN keywords ON
       keywords_products.keyword_rec_id = keywords.keyword_rec_id
WHERE (keywords.keyword LIKE '%purchased%' OR
       keywords.keyword LIKE '%item%')

我有三个SQLite表,一个产品表,一个keywords_products表和一个关键字表。

CREATE TABLE products (
    product_rec_id  INTEGER  PRIMARY KEY  NOT NULL,
    name            VARCHAR (100)  NOT NULL
);

CREATE TABLE keywords_products (
    keyword_rec_id INTEGER NOT NULL,
    product_rec_id INTEGER NOT NULL
);

CREATE TABLE keywords (
    keyword_rec_id INTEGER  PRIMARY KEY  NOT NULL,
    keyword        VARCHAR (50)  NOT NULL  UNIQUE
);

keywords_products 表包含产品的记录ID和关键字的记录ID。可以在关键字表中为每个产品分配多个关键字。

关键字表如下所示:

keyword_rec_id  keyword
--------------  -----------
60              melee
43              scifi
87              water

keywords_products 表看起来像这样(一个关键字可以分配给许多产品):

keyword_rec_id  product_rec_id
--------------  --------------
43              1
60              1
43              2
87              3

产品表如下所示:

product_rec_id  name
--------------  --------------
1               Scifi Melee Weapons
2               Scifi Ray Weapon
3               Lake House

2 个答案:

答案 0 :(得分:0)

您必须使用具有多个WHEN分支的单个CASE表达式。

制作不同CASE表达式的布尔函数是没有意义的 - CASE本身不是布尔函数。

您可以在https://firebirdsql.org/refdocs/langrefupd15-case.html

查看规则和示例
case
  when Age >= 18 then 'Yes'
  when Age <  18 then 'No'
end;

在此模式之后,将两个CASE子句重写为单个CASE子句。

但是,如果无法将过滤器和条件移动到SQL select的标准部分,则只使用CASE。正常的方法是使用预过滤来最小化SQL引擎必须获取的数据。 CASE使用后过滤,它使SQL引擎获取所有数据,无论是否需要,然后丢弃不需要的获取数据。这是减缓这一过程的多余工作。

在你的情况下,你已经将条件提取到WHERE子句中,这很好。

SELECT
...

WHERE (keywords.keyword LIKE '%purchased%') 
   OR (keywords.keyword LIKE '%item%') 

由于您预先过滤数据流以始终包含“item”或“purchase”,因此您的CASE子句将始终在此WHERE预过滤下选择的所有行上返回1。因此 - 只需删除冗余CASE子句并改为使用“1”。

SELECT Count(1)
FROM products
  LEFT JOIN keywords_products ON products.product_rec_id = keywords_products.product_rec_id
  LEFT JOIN keywords ON keywords_products.keyword_rec_id = keywords.keyword_rec_id
WHERE (keywords.keyword LIKE '%purchased%') 
   OR (keywords.keyword LIKE '%item%') 

现在,假定在JOINing之后逻辑处理WHERE子句,这个查询事实上将LEFT JOIN转换为FULL JOIN(您的WHERE子句只丢弃具有NULL“关键字”列值的行)但是在不可靠且效率低下的方法中。因为你不想让“关键字是NULL”类行 - 只需将你的左连接转换为普通连接。

答案 1 :(得分:0)

我假设您想要计算两个条件均为真的行数。

发生错误是因为您无法在整数值之间使用AND。值必须是真正的布尔值。

所以,将代码更改为

Count((CASE WHEN keywords.keyword LIKE '%purchased%'
          THEN TRUE END) AND
         (CASE WHEN keywords.keyword LIKE '%item%'
          THEN TRUE END))

然而,这太复杂了。您可以将表达式简化为

count(nullif(
    keywords.keyword LIKE '%purchased%' and keywords.keyword LIKE '%item%',
    false))

需要使用NULLIF,因为COUNT将计算所有非NULL值(根据SQL标准的要求),false也是非NULL。因此,为了实现(假设的)预期效果,我们使用falseNULL转换为NULLIF