【问题标题】:Count returns different results for similar set of tables, why?计数对于相似的表集返回不同的结果,为什么?
【发布时间】:2018-03-30 13:58:00
【问题描述】:

我需要计算 product_rec_id 匹配、分配两个或多个供应商名称的次数。

例如,当用户输入 sarsabobbie25 时,我应该从下面的示例供应商表格中获得值计数 1。

这就是我所拥有的,对我来说奇怪的是,这两种方法适用于关键字的表格,但不适用于供应商的表格,Count 总是返回值 0。这些表格实际上是相似的,可能是什么问题?

SELECT
  Count(distinct product_rec_id)
FROM
  vendors
  INNER JOIN vendors_products ON vendors_products.vendor_rec_id = vendors.vendor_rec_id
WHERE
  (vendors.name LIKE '%sarsa%') AND
  (vendors.name LIKE '%bobbie25%')

对于 Firebird 3,我将 Then 1 更改为 Then True

SELECT
  Count((CASE
    WHEN vendors.name LIKE '%sarsa%'
    THEN 1
  END) AND (CASE
    WHEN vendors.name LIKE '%bobbie25%'
    THEN 1
  END)) AS TRows
FROM
  vendors
  INNER JOIN vendors_products ON vendors_products.vendor_rec_id = vendors.vendor_rec_id
WHERE
  (vendors.name LIKE '%sarsa%' OR
    vendors.name LIKE '%bobbie25%')

-

CREATE TABLE vendors (
    vendor_rec_id     INTEGER       PRIMARY KEY NOT NULL,
    company_broker_id INTEGER       NOT NULL,
    name              VARCHAR (50)  NOT NULL,
    vendor_id         VARCHAR (50),
    store_url         VARCHAR (255),
    website_url       VARCHAR (255) 
);

CREATE TABLE vendors_products (
    product_rec_id INTEGER NOT NULL,
    vendor_rec_id  INTEGER
);

-

vendors' table data:
        60 2 bobbie25 73658 http://www.somewebsite.com/ http://www.somewebsite.com/
        43 2 sarsa    61688 http://www.somewebsite.com/ http://www.somewebsite.com/

-

CREATE TABLE keywords (
    keyword_rec_id INTEGER      PRIMARY KEYNOT NULL,
    keyword        VARCHAR (50) NOT NULL UNIQUE,
    chart          INTEGER      NOT NULL
                                DEFAULT 0
);
CREATE TABLE keywords_products (
    keyword_rec_id INTEGER NOT NULL,
    product_rec_id INTEGER
);

vendors 表中的 vendor_rec_id 和 name 字段如下所示,这是 vendors 表的示例(永远不会有任何空值):

vendor_rec_id  name
--------------  -----------
60              bobbie25
43              sarsa
87              johnf

vendors_products 表中的 vendor_rec_id 和 product_rec_id 如下所示(一个供应商名称可以分配给多个产品)(永远不会有任何空值):

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

【问题讨论】:

  • 在您的第一个查询中,vendor.names 是否应该同时类似于 '%sarsa%' AND '%bobbie25%'?它可以是 1 中的任何一个,并且计数将始终为 0。
  • 那么为什么它可以毫无问题地使用关键字的表格呢?它总是按我的预期计算。
  • vendors 表的内容是什么,请更明确哪些有效,哪些无效。以及您的期望以及原因。正如您在上一个问题中提到的,您使用count(case ... and case ...) 的整个构造没有多大意义,但我们不能提出替代方案,因为目前还不清楚您真正想要做什么。同样在您提到的文本中“当用户进入混战和科幻时”,但您的示例过滤了供应商名称。请让您的问题自洽。
  • 我编辑了我的问题。
  • 问题在于,您所呈现的条件只会计算两个条件都为真在同一行的行,而这永远不会是案子。为什么计数不够好?

标签: sql sqlite count firebird-3.0


【解决方案1】:

这是我最终设法完成的。这没有问题。

现在,当用户输入多个关键字并想要提取与输入的所有关键字匹配的记录时,我可以使用这个来获取记录计数和记录本身(没有 Count(*) Select)。

我确信有更好的方法来完成这项工作,但这是我有限的 SQL 经验让我明白的。

Select Count(*) As TRows From
(Select
  vendors_products.product_rec_id
From
  vendors_products
  Inner Join vendors On vendors_products.vendor_rec_id = vendors.vendor_rec_id
Where
  (Lower(vendors.name) Like '%sarsa%' OR
    Lower(vendors.name) Like '%bobbie25%')
Group By
  vendors_products.product_rec_id
Having
  Sum(Case
    When lower(vendors.name) Like '%sarsa%'
    Then 1
    Else 0
  End) > 0 And
  Sum(Case
    When lower(vendors.name) Like '%bobbie25%'
    Then 1
    Else 0
  End) > 0
) MyCountResults

【讨论】:

  • 您可以考虑使用单个sum(case when lower(vendors.name) Like '%sarsa%' then 1 when lower(vendors.name) Like '%bobbie25%' then 1 else 0 end) >= 2;不过可能不会有太大的不同。
【解决方案2】:

最简单的解决方案是选择所有在vendors_products 中有条目且具有给定供应商名称的产品。

假设一个表products 有一个列product_id,你可以这样做

  1. 为您要检查的每个供应商使用exists

    with product_by_vendor as (
        select vp.product_rec_id, v.name
        from vendors v
        inner join vendors_products vp on v.vendor_rec_id = vp.vendor_rec_id
    )
    select count(*)
    from products p
    where exists (
        select * 
        from product_by_vendor 
        where product_rec_id = p.product_id
        and name like '%sarsa%')
    and exists (
        select * 
        from product_by_vendor 
        where product_rec_id = p.product_id
        and name like '%bobbie25%')
    
  2. 您要检查的每个供应商的inner join

    with product_by_vendor as (
        select vp.product_rec_id, v.name
        from vendors v
        inner join vendors_products vp on v.vendor_rec_id = vp.vendor_rec_id
    )
    select count(*)
    from products p
    inner join product_by_vendor pv1 
        on pv1.product_rec_id = p.product_id and pv1.name like '%sarsa%'
    inner join product_by_vendor pv2 
        on pv2.product_rec_id = p.product_id and pv2.name like '%bobbie25%'
    
  3. 使用 cross joinALL 谓词稍微更晦涩(和 Firebird 特定):

    with product_by_vendor as (
        select vp.product_rec_id, v.name, v.vendor_rec_id
        from vendors v
        inner join vendors_products vp on v.vendor_rec_id = vp.vendor_rec_id
    ),
    vendors_x_products as (
        select p.product_id, v.name, v.vendor_rec_id
        from products p
        cross join vendors v
    )
    select count(*)
    from products p
    where p.product_id = all (
        select pv.product_rec_id 
        from vendors_x_products vp
        left join product_by_vendor pv
            on vp.product_id = pv.product_rec_id and vp.vendor_rec_id = pv.vendor_rec_id
        where vp.product_id = p.product_id
        and (vp.name like '%sarsa%' or vp.name like '%bobbie25%')
    )
    

我相信可能有更简单的方法,但我现在想不出。

【讨论】:

  • 非常感谢您抽出宝贵时间帮助我。我会研究这些。然而,我做了几个测试,我注意到这些比我放在一起的解决方案做的更多。最后一个进入数十万。当然,它们在索引上完成的次数比我的解决方案多,但在这种情况下,我的解决方案大约执行 500 次。这是因为我的解决方案是使用 Group By 并在内存中做更多事情吗?
  • @nDelphi 最后一个在有很多记录时可能效率不高,因为它使用了cross join。很难说更多的获取是好是坏,因为值将取决于页面是否缓存在内存中(您可能需要多次执行查询以查看值如何变化)。
猜你喜欢
  • 2017-04-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-12
  • 1970-01-01
  • 2012-07-28
  • 2013-03-10
  • 1970-01-01
  • 2023-03-22
相关资源
最近更新 更多