0

嗨,我正在寻找以下自反式交叉连接的替代语法。目标是表格的一种行填充器 - 日期应该有每个 CDN 的条目。我正在使用 MySQL

select 
  d.labelDate, 
  n.cdn,
  networks.sites
from (
  select 
    distinct labelDate 
  from 
    cdn_trend
) as d
cross join (
  select 
    distinct cdn 
  from cdn_trend
) as n
left join cdn_trend as networks 
  on  networks.labelDate = d.labelDate
  and networks.cdn = n.cdn    
order by 
  labelDate, 
  cdn

我已经尝试使用简单的别名来重铸交叉连接,但这给了我连接中的列错误。是否可以这样做或者我应该考虑使用视图来代替?

由于交叉连接应该简单地返回两个表的笛卡尔积,因此它应该与在没有连接的情况下简单地选择两者相同。但是,以下引发了“on 子句中的未知列 d.labelDate”异常

select distinct d.labelDate, n.cdn, networks.sites
from 
cdn_trend as d,
cdn_trend as n
left join cdn_trend as networks ON
(n.labelDate = networks.labelDate
and d.cdn = networks.cdn)
order by labelDate, cdn

Error Code: 1054. Unknown column 'd.cdn' in 'on clause'

因为长度dn都比较小,所以查询的大小是足够快的。

4

3 回答 3

0

在玩了一些之后,这是我能想到的最好的。似乎可以对表名进行参数化,但会涉及另一层语句生成,幸运的是,这个项目不需要。

-- --------------------------------------------------------------------------------
-- Routine DDL
-- Note: comments before and after the routine body will not be stored by the server
-- --------------------------------------------------------------------------------
DELIMITER $$

CREATE DEFINER="root"@"localhost" PROCEDURE "cdn_pivot"(
    IN slice varchar(64),
    IN start date,
    IN stop date)

BEGIN

SET @@group_concat_max_len = 32000;
SET @sql = NULL;

SELECT
  GROUP_CONCAT(DISTINCT
    CONCAT(
    ' sum(IF(cdn = ''',
        cdn,
        ''', sites,NULL)) "'
        ,cdn, '"'
    )
  ) INTO @sql
FROM cdns ORDER BY sites;

SET @stmt = CONCAT('SELECT labelDate, ',
@sql,
' from cdns 
WHERE slice = ''',
slice,
''' AND ( labelDate between''',
start,
''' AND ''',
stop,
'''
) 
GROUP BY labelDate');

prepare stmt from @stmt;
execute stmt;
deallocate prepare stmt;

SET @@group_concat_max_len = 1024;
END

这可以简单地称为例如。 call cdn_pivot('Top100', '2013-01-01', 2013-02-01')

考虑到与测试此代码相关的问题并将其与任何客户端代码一起保存,在客户端上生成头部的动态部分非常诱人,至少对于这种用例,附加查询的性能损失应该不要太高。关键显然是了解如何动态生成列。

于 2013-05-21T14:07:26.557 回答
0

阅读评论和额外信息,您需要一个带有 y -lableDate和 x -cdn和值的枢轴 -sites假设值为cdn(a,b,c) 并​​且这sites是一个数字,您可以试试这个:

SELECT
    labelDate,
    SUM(IF(cdn = 'a',sites,0)) as cdn_a,
    SUM(IF(cdn = 'b',sites,0)) as cdn_b,
    SUM(IF(cdn = 'c',sites,0)) as cdn_c
FROM 
    cdn_trend
GROUP BY
    labelDate

输出应该是这样的(我使用了你的样本数据):

labelDate   cdn_a   cdn_b   cdn_c
2013-04     NULL    5       4
2013-05     6       NULL    NULL
....
于 2013-05-16T07:18:34.340 回答
0

我认为您的初衷很接近...对于每个日期,您都需要每个网络节点状态的结果。如果您在没有连接条件的 WHERE 子句中列出多个表,则默认情况下它将创建一个笛卡尔...从那里,连接到您的详细信息表...

select 
      d.labelDate, 
      n.cdn,
      networks.sites
   from 
      ( select d.LabelDate, n.cdn
           from 
              ( select distinct labelDate 
                   from cdn_trend ) as d,
              ( select distinct cdn 
                   from cdn_trend ) as n ) as CrossResults
         LEFT JOIN cdn_trend as networks 
         on  CrossResults.labelDate = networks.labelDate
         and CrossResults.cdn = networks.cdn
   order by 
      networks.labelDate, 
      networks.cdn
于 2013-05-15T17:36:41.007 回答