Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/238.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 复杂MySQL查询中的排序和分组_Php_Mysql_D3.js - Fatal编程技术网

Php 复杂MySQL查询中的排序和分组

Php 复杂MySQL查询中的排序和分组,php,mysql,d3.js,Php,Mysql,D3.js,我需要执行一组相当复杂的MySQL查询,从分配给不同音乐艺术家的标签数据库中生成适合在D3中绘制的数据。相关表格中的行(称为“lastfm_注释”)为:user_id、artist_id、tag_id和tag_month(即,我们记录了许多特定用户在特定时间使用特定标签标记特定艺术家的实例)。这一切都嵌入到php脚本中 最后我需要生成一个JSON对象,该对象包含给定范围内的日期,给定艺术家的每个唯一标记在该月使用的次数(包括未使用给定标记的日期的计数为零) 这就是我目前所拥有的(假设$itemI

我需要执行一组相当复杂的MySQL查询,从分配给不同音乐艺术家的标签数据库中生成适合在D3中绘制的数据。相关表格中的行(称为“lastfm_注释”)为:user_id、artist_id、tag_id和tag_month(即,我们记录了许多特定用户在特定时间使用特定标签标记特定艺术家的实例)。这一切都嵌入到php脚本中

最后我需要生成一个JSON对象,该对象包含给定范围内的日期,给定艺术家的每个唯一标记在该月使用的次数(包括未使用给定标记的日期的计数为零)

这就是我目前所拥有的(假设$itemID和artist_id在这里是可互换的):

(结束编辑。)

这是可行的,但(至少)有两个大问题我不能完全弄清楚。首先,在大而丑陋的SQL查询中,我在调用

(select distinct tag_id from lastfm_annotations where artist_id='" . $itemID . "')
每次我通过循环时,即使每次的值都是相同的。你知道我如何解决这个问题吗?也许有可能以某种方式将唯一的tag_id保存为php数组,然后将其插入到查询中

第二,我需要确保标签总是按其总频率排序(即,在所有时间内,而不仅仅是在某个月内),但我不确定如何做到这一点。我可以使用如下查询获得正确的顺序:

select tag_id, count(*) as freq from lastfm_annotations where item_id=XXX order by freq desc
但我需要确保循环中的每个查询都以相同的顺序返回标记。有什么想法吗?也许在我实际开始绘制数据时,在d3中处理排序会更好,但如果在我进行SQL调用时数据以正确的顺序开始,则会更好


对于这个大问题,很抱歉,谢谢您的帮助!

这里有一个查询,将为每个艺术家执行一次,而不是每个艺术家月的组合。它通过加入
artist\u id
上的子查询,然后在where子句中过滤
artist\u id=$itemID
来解决您的第一个问题。DB引擎应该当它处理查询时,条件会被分解到子查询中,因此它不会像看上去那样低效,而且因为它不是在一个月循环内调用的,所以总体上应该做的工作更少

第二个问题是通过从第一个子查询中获取总体频率,并按该频率降序排列整个结果集来解决的,这将把标记最多的月份放在第一位

这样做的缺点是没有标记的月份不会显示在结果中。您可以在应用程序逻辑中解决这一问题(例如,跟踪每个标记在您的日期范围内没有看到的月份,然后合成“0”行)。也可以将查询扩展到包含缺少的月份,但由于复杂性,除非您感兴趣,否则我不会详细介绍

select t1.tag_id
     , t2.tag_month
     , t2.freq as month_freq
     , t1.freq as total_freq
  from (select tag_id
             , artist_id
             , count(*) as freq
          from lastfm_annotations
         group by tag_id, artist_id) t1
       inner join
       (select tag_id
             , tag_month
             , artist_id
             , count(*) as freq
          from lastfm_annotations 
         group by tag_id, tag_month, artist_id) t2
       on t1.artist_id = t2.artist_id and t1.tag_id = t2.tag_id
 where t2.tag_month between '$dateRangeStart' and '$dateRangeEnd'
   and t1.artist_id = '$itemID'
 order by total_freq desc, t1.tag_id

感谢编辑Alanyst-现在可读性更强。旁注:您可以使用更简洁的
ifnull(t1.freq,0)
而不是t1.freq为null时的
情况,则查询中的0 else t1.freq end
。如果标记“foo”在特定月份用于艺术家A,但从未用于艺术家B,那么艺术家B的结果是否应该有标记“foo”的行(带有
freq
==0),或者B的结果应该只包含用于B的标签吗?B的结果应该只包含用于艺术家B的标签(至少总共一次).原则上,我不介意在数据库中使用频率为零的其他标记,但数据库中有大约一百万个唯一标记,因此这将使数据结构不合理地大(且稀疏)。这似乎工作得很好-谢谢!我唯一做的编辑是也按tag_month订购,但这是一个非常小的更改。我唯一关心的是执行时间…我使用一个任意的艺术家ID运行此程序,并花费了大约2小时的时间生成结果…我的目标是将其部署到交互式可视化工具中,但这不是真正的po这种执行时间是不可能的。仍然接受,因为它回答了我所有的问题。但是,如果您对执行时间问题有任何想法,我们将不胜感激。表上有哪些索引?用户id+项目id+标记id上的复合主键,加上(非唯一)关于项目id、艺术家id、标签id和标签月份的索引。其中一些可能是多余的,因为我已经调整了DB结构一段时间。为了澄清问题,每个项目(专辑、艺术家或歌曲)都有一个唯一的id,但每个注释(标记项目的实例)有一个关联的艺术家id。下面是db结构的屏幕截图,可以让事情更清楚:,。哦,你可以忽略“tag_date”列。只使用“tag_month”。请记住,该表总共有5000万条条目。
select tag_id, count(*) as freq from lastfm_annotations where item_id=XXX order by freq desc
select t1.tag_id
     , t2.tag_month
     , t2.freq as month_freq
     , t1.freq as total_freq
  from (select tag_id
             , artist_id
             , count(*) as freq
          from lastfm_annotations
         group by tag_id, artist_id) t1
       inner join
       (select tag_id
             , tag_month
             , artist_id
             , count(*) as freq
          from lastfm_annotations 
         group by tag_id, tag_month, artist_id) t2
       on t1.artist_id = t2.artist_id and t1.tag_id = t2.tag_id
 where t2.tag_month between '$dateRangeStart' and '$dateRangeEnd'
   and t1.artist_id = '$itemID'
 order by total_freq desc, t1.tag_id