0

经过一番搜索和阅读后,我为我的应用程序提出了以下 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字段属于类型DATE,并且UserAge是从该日期字段计算年龄的函数。

表结构如下:

[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 查询来实现相同的结果。基本上我会添加更多类似上面的行,但条件不同,特别是在日期上。

4

2 回答 2

3

您可以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

可以稍微简化一下吗?

于 2011-01-05T01:44:16.083 回答
0

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

可能值得以下列方式重新排列它。由于所有条件都依赖于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;

不过,总的来说,我可能会保留您的查询原样。您拥有的查询很容易理解,并且可能执行得相当好。

于 2011-01-05T12:58:28.130 回答