搜索和阅读后,我想到了我的应用程序以下SQL查询:

SELECT
  ROUND(AVG(CASE WHEN gender = 'M' THEN rating END), 1) avgAllM,
  COUNT(CASE WHEN gender = 'M' THEN rating END) countAllM,
  ROUND(AVG(CASE WHEN gender = 'F' THEN rating END), 1) avgAllF,
  COUNT(CASE WHEN gender = 'F' THEN rating END) countAllF,
  ROUND(AVG(CASE WHEN gender = 'M' AND UserAge(birth_date) <= 18 THEN rating END), 1) avgU18M,
  COUNT(CASE WHEN gender = 'M' AND UserAge(birth_date) <= 18 THEN rating END) countU18M,
  ROUND(AVG(CASE WHEN gender = 'F' AND UserAge(birth_date) <= 18 THEN rating END), 1) avgU18F,
  COUNT(CASE WHEN gender = 'F' AND UserAge(birth_date) <= 18 THEN rating END) countU18F
FROM movie_ratings mr INNER JOIN accounts a
  ON mr.aid = a.aid
WHERE mid = 5;

我想知道如果可能的话,我该如何简化这一点。这 birth_date 字段是类型 DATEUserAge 是从该日期字段计算年龄的功能。

表结构如下:

[ACCOUNTS]
aid(PK), birth_date, gender

[MOVIE_RATINGS]
mid(PK), aid(PK,FK), rating

我正在寻找两件事:

  • 对上述代码的一般简化,更有经验的用户知道我不知道。
  • 我正在使用PHP进行此操作,对于每个记录,我都会有一个与所有这些变量的关联阵列。我正在寻找一种将它们分组为多维数组的方法,因此PHP代码易于阅读。当然,我不想在PHP本身中这样做,这将是毫无意义的。

例如,这样的事情:

$info[0]['avgAllM']
$info[0]['countAllM']
$info[1]['avgAllF']
$info[1]['countAllF']
$info[2]['avgU18M']
$info[2]['countU18M']
$info[3]['avgU18F']
$info[3]['countU18F']

代替:

$info['avgAllM']
$info['countAllM']
$info['avgAllF']
$info['countAllF']
$info['avgU18M']
$info['countU18M']
$info['avgU18F']
$info['countU18F']

我什至不知道这是否可能,所以我真的想知道它是否以及如何完成。

为什么我想要所有这些?好吧,上面的SQL查询只是我需要做的完整SQL的片段。我还没有这样做,因为在进行所有工作之前,我想知道是否有更紧凑的SQL查询以实现相同的结果。基本上,我将添加其他类似上述线的行,但有不同的条件,特别是在日期。

有帮助吗?

解决方案

您可以创建一个 VIEW 具有以下定义

SELECT
      CASE WHEN gender = 'M' THEN rating END AS AllM,
      CASE WHEN gender = 'F' THEN rating END AS AllF,
      CASE WHEN gender = 'M' AND UserAge(birth_date) <= 18 THEN rating END AS U18M,
      CASE WHEN gender = 'F' AND UserAge(birth_date) <= 18 THEN rating END AS U18F
      FROM movie_ratings mr INNER JOIN accounts a
        ON mr.aid = a.aid
      WHERE mid = 5

然后从中选择

SELECT ROUND(AVG(AllM), 1) avgAllM,
       COUNT(AllM)         countAllM,
       ROUND(AVG(AllF), 1) avg,
       COUNT(AllF)         countAllF,
       ROUND(AVG(U18M), 1) avgU18M,
       COUNT(U18M)         countU18M,
       ROUND(AVG(U18F), 1) avgU18F,
       COUNT(U18F)         countU18F
FROM  yourview

可能会稍微简化事情吗?

其他提示

这可能只是优化过早的情况。该查询可以完成您需要的工作,并且只是看起来很复杂,因为它确实很复杂。我不确定是否有任何技巧会有所帮助。这可能取决于数据的特征。查询慢吗?您认为可能会更快吗?

可能值得以以下方式重新安排它。由于所有条件都取决于 ACCOUNTS 我认为的表格将大大小于 MOVIE_RATINGS 表您可能可以在较小的数据集上完成所有计算,这可能会更快。虽然如果您一次只选择一部电影(mid = 5)那可能不会。

我不确定这会起作用,但认为应该这样做。

SELECT
  ROUND(AVG(rating * AllM), 1) avgAllM,
  COUNT(rating * AllM) countAllM,
  ROUND(AVG(rating * AllF), 1) avgAllF,
  COUNT(rating * AllF) countAllF,
  ROUND(AVG(rating * AllM * U18), 1) avgU18M,
  COUNT(rating * AllM * U18) countU18M,
  ROUND(AVG(rating * AllM * U18), 1) avgU18F,
  COUNT(rating * AllM * U18) countU18F
FROM 
  movie_ratings mr 
  INNER JOIN (
    select 
      aid,
      case when gender = 'M' then 1 end as AllM,
      case when gender = 'F' then 1 end as AllF,
      case when UserAge(birth_date) <= 18 then 1 end as U18
    from accounts) a ON mr.aid = a.aid
WHERE mid = 5;

不过,总而言之,我可能只会离开您的查询。您拥有的查询易于理解,并且可能表现良好。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top