设计和查询产品/评审系统

时间:2016-10-31 16:08:52

标签: sql sql-server database-schema review

我从头开始创建了一个产品/评论系统,我很难在SQL Server中执行以下查询。

我的架构有不同的表格,用于:产品,评论,类别,productPhotos和品牌。我必须查询它们以查找品牌和类别名称,照片详细信息,平均评分和评论数量。

我很难获得评论和平均评分。

可以隐藏(用户已删除)或屏蔽(等待审核)。我的产品表没有评论数或平均评分列,所以我需要在该查询上计算,但不计算被阻止和隐藏的数据(r.bloqueado = 0和r.hidden = 0)。

我有下面的查询,但它计算被阻止和隐藏。如果我取消注释“和r.bloqueado = 0和r.hidden = 0”部分我得到了正确的计数,但是它没有显示有0评论的产品(我需要的东西!)。

select top 20 
    p.id, p.brand, m.nome, c.name, 
    count(r.product) AS NoReviews, Avg(r.nota) AS AvgRating, 
    f.id as cod_foto,f.nome as nome_foto 
from
    tblBrands AS m 
inner join 
    (tblProducts AS p 
left join 
    tblProductsReviews AS r ON p.id = r.product) ON p.brand = m.id 
left join 
    tblProductsCategorias as c on p.categoria = c.id 
left join 
    (select 
         id_product, id, nome 
     from 
         tblProductsFotos O 
     where 
         id = (SELECT min(I.id) 
               FROM tblProductsFotos I 
               WHERE I.id_product = O.id_product)) as f on p.id = f.id_product 
where 
    p.bloqueado = 0
    //Problem - and r.bloqueado=0 and r.hidden=0    
group by 
    p.id, p.brand, p.modalidade, m.nome, c.name, f.id,f.nome"

需要您的建议:

我见过其他系统在产品表中有平均等级和评论数。这将有助于此查询的复杂性(可能还有性能),但是我必须在每个新的审核,阻止和隐藏操作中执行额外的查询。我可以轻松地做到这一点。考虑到包含和更新比显示产品少得多,这听起来不错。 这样做会更好吗?

或者找到修复此查询的方法更好吗?你能帮我找个解决方案吗?

由于

2 个答案:

答案 0 :(得分:0)

为了计算产品的数量你可以使用的情况和总和分配1那里的值不是r.bloqueado = 0或r.hidden = 0和0这些值(所以你可以避免过滤器在哪里)< / p>

  "select top 20 p.id, p.brand, m.nome, c.name, sum(
                              case  when  r.bloqueado=0 then 0 
                                    when  r.hidden=0 then 0 
                                    else 1 
                              end )  AS NoReviews, 
  Avg(r.nota) AS AvgRating, f.id as cod_foto,f.nome as nome_foto 
  from tblBrands AS m 
  inner join (tblProducts AS p 
  left join tblProductsReviews AS r ON p.id=r.product ) ON p.brand = m.id 
  left join tblProductsCategorias as c on p.categoria=c.id 
  left join (select id_product,id,nome from tblProductsFotos O 
  where id = (SELECT min(I.id) FROM tblProductsFotos I 
            WHERE I.id_product = O.id_product)) as f on p.id = f.id_product where p.bloqueado=0
  group by p.id, p.brand, p.modalidade, m.nome, c.name, f.id,f.nome"

对于平均可能你可以做类似的事情

答案 1 :(得分:0)

将where子句与外连接组合时,很容易丢失记录。外表中不存在的行将返回NULL。您的过滤器意外地排除了这些空值。

以下是一个展示正在发生的事情的例子:

/* Sample data.
 * There are two tables: product and review.
 * There are two products: 1 & 2.
 * Only product 1 has a review.
 */
DECLARE @Product TABLE
    (
        ProductId   INT
    )
;

DECLARE @Review TABLE
    (
        ReviewId    INT,
        ProductId   INT,
        Blocked     BIT
    )
;

INSERT INTO @Product
    (
        ProductId
    )
VALUES
    (1),
    (2)
;

INSERT INTO @Review
    (
        ReviewId,
        ProductId,
        Blocked
    )
VALUES
    (1, 1, 0)
;

在没有where子句的情况下连接表的外部返回:

<强>查询

-- No where.
SELECT
    p.ProductId,
    r.ReviewId,
    r.Blocked
FROM
    @Product AS p   
        LEFT OUTER JOIN @Review AS r        ON r.ProductId = p.ProductId
;

<强>结果

ProductId   ReviewId    Blocked
1           1           0
2           NULL        NULL

过滤Blocked = 0会删除第二条记录,因此会ProductId 2.而是:

-- With where.
SELECT
    p.ProductId,
    r.ReviewId,
    r.Blocked
FROM
    @Product AS p   
        LEFT OUTER JOIN @Review AS r        ON r.ProductId = p.ProductId
WHERE
    r.Blocked = 0
    OR r.Blocked IS NULL
;

此查询保留NULL值,ProductId 2.您的示例稍微复杂一点,因为您有两个字段。

SELECT
    ...
WHERE
    (
        Blocked = 0
        AND Hidden = 0
    )
    OR Blocked IS NULL
;

您不需要检查两个字段是否为NULL,因为它们出现在同一个表中。