多个MySQL查询到单个插入

时间:2014-03-25 23:36:42

标签: mysql

我试图执行大量MySQL查询并将结果作为一行写入不同的数据库和表。

所以这是有效的

INSERT INTO bridgedb.stats (longestcall, totalmins, totalconfs)
SELECT
(SELECT MAX(duration) AS longestcall FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),

(SELECT SUM(duration) AS totalmins FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),

(SELECT COUNT(*) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY);

这是有效的

INSERT INTO bridgedb.stats (date, peakchan)
SELECT
  `calldate`,
  MAX(concurrent)+1 AS peakcount
FROM (
    SELECT
      DATE(a.calldate) as calldate,
      COUNT(b.uniqueid) AS concurrent
    FROM asteriskcdr.cdr AS a, asteriskcdr.cdr AS b
    WHERE  
      a.calldate >= NOW() - INTERVAL 4 DAY
      AND (
        (a.calldate<=b.calldate AND (UNIX_TIMESTAMP(a.calldate)+a.duration)>=UNIX_TIMESTAMP(b.calldate))
        OR (b.calldate<=a.calldate AND (UNIX_TIMESTAMP(b.calldate)+b.duration)>=UNIX_TIMESTAMP(a.calldate))
      )
      AND a.uniqueid>b.uniqueid
    GROUP BY a.uniqueid
  ) AS baseview
GROUP BY calldate;

但这不起作用

INSERT INTO bridgedb.stats (date, peakchan, longestcall, totalmins, totalconfs)
SELECT
(SELECT
      `calldate`,
      MAX(concurrent)+1 AS peakcount
    FROM (
        SELECT
          DATE(a.calldate) as calldate,
          COUNT(b.uniqueid) AS concurrent
        FROM asteriskcdr.cdr AS a, asteriskcdr.cdr AS b
        WHERE  
          a.calldate >= NOW() - INTERVAL 1 DAY
          AND (
            (a.calldate<=b.calldate AND (UNIX_TIMESTAMP(a.calldate)+a.duration)>=UNIX_TIMESTAMP(b.calldate))
            OR (b.calldate<=a.calldate AND (UNIX_TIMESTAMP(b.calldate)+b.duration)>=UNIX_TIMESTAMP(a.calldate))
          )
          AND a.uniqueid>b.uniqueid
        GROUP BY a.uniqueid
      ) AS baseview
    GROUP BY calldate),

(SELECT MAX(duration) AS longestcall FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),

(SELECT SUM(duration) AS totalmins FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),

(SELECT COUNT(*) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY);

我收到错误#1241 - 操作数应包含1列

有谁知道我如何才能使这项工作适用于所有查询?

2 个答案:

答案 0 :(得分:0)

尝试使用会话变量或将其抽象为存储过程,例如 -

首先:

SELECT
  @calldate:=`calldate`,
  @peakchan:=MAX(concurrent)+1
FROM (
  ...
) AS baseview
GROUP BY calldate

第二

SELECT @longestcall:=MAX(duration) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY

第三

SELECT @totalmins:=SUM(duration)  FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY

第四:

SELECT @totalconfs:=COUNT(*) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY;

最后

INSERT INTO bridgedb.stats (date, peakchan, longestcall, totalmins, totalconfs)
VALUES (@calldate, @peakchan, @longestcall, @totalmins, @totalconfs)

BTW:调用专栏date不是一个好主意。

修改

当然,您需要确保这些查询在同一会话中运行以使用会话变量。这是在PHP中使用单个数据库连接运行时的默认值

编辑2

要处理没有活动的时段,您可以

  • 使用SELECT @calldate:=DATE(NOW() - INTERVAL 1 DAY), @peakchan:=0, @longestcall:=0, @totalmins:=0, @totalconfs:=0;(创建默认值的记录)
  • 作为前缀
  • 或在第一次查询后停止,如果@calldate为NULL(未创建记录)

编辑3

这对我有用:

DELIMITER //

CREATE PROCEDURE ReportYesterday()
BEGIN
  DECLARE calldate DATE;
  DECLARE peakchan, longestcall, totalmins, totalconfs INT;

SELECT
  @calldate:=`calldate`,
  @peakchan:=MAX(concurrent)+1
FROM (
       SELECT
          DATE(a.calldate) as calldate,
          COUNT(b.uniqueid) AS concurrent
        FROM asteriskcdr.cdr AS a, asteriskcdr.cdr AS b
        WHERE  
          a.calldate >= NOW() - INTERVAL 1 DAY
          AND (
            (a.calldate<=b.calldate AND (UNIX_TIMESTAMP(a.calldate)+a.duration)>=UNIX_TIMESTAMP(b.calldate))
            OR (b.calldate<=a.calldate AND (UNIX_TIMESTAMP(b.calldate)+b.duration)>=UNIX_TIMESTAMP(a.calldate))
          )
          AND a.uniqueid>b.uniqueid
        GROUP BY a.uniqueid) AS baseview
GROUP BY calldate
;

-- EDIT 4 IS THE FOLLOWING LINE 

IF @calldate IS NOT NULL THEN

  SELECT @longestcall:=MAX(duration) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY
  ;

  SELECT @totalmins:=SUM(duration)  FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY
  ;

  SELECT @totalconfs:=COUNT(*) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY
  ;

  INSERT INTO bridgedb.stats (date, peakchan, longestcall, totalmins, totalconfs)
  VALUES (@calldate, @peakchan, @longestcall, @totalmins, @totalconfs)
  ;

END IF;

END
;
//

DELIMITER ;

接着是

CALL ReportYesterday();

答案 1 :(得分:0)

您必须构建一个返回所有行的(有效)SELECT查询。您之前的SELECT无效。这应该工作:

INSERT INTO bridgedb.stats (date, peakchan, longestcall, totalmins, totalconfs)
SELECT
      `calldate`,
      MAX(concurrent)+1 AS peakcount,
(SELECT MAX(duration) AS longestcall FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),
(SELECT SUM(duration) AS totalmins FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY),
(SELECT COUNT(*) FROM bridgedb.log WHERE `start` >= NOW() - INTERVAL 1 DAY)
    FROM (
        SELECT
          DATE(a.calldate) as calldate,
          COUNT(b.uniqueid) AS concurrent
        FROM asteriskcdr.cdr AS a, asteriskcdr.cdr AS b
        WHERE  
          a.calldate >= NOW() - INTERVAL 1 DAY
          AND (
            (a.calldate<=b.calldate AND (UNIX_TIMESTAMP(a.calldate)+a.duration)>=UNIX_TIMESTAMP(b.calldate))
            OR (b.calldate<=a.calldate AND (UNIX_TIMESTAMP(b.calldate)+b.duration)>=UNIX_TIMESTAMP(a.calldate))
          )
          AND a.uniqueid>b.uniqueid
        GROUP BY a.uniqueid
      ) AS baseview
    GROUP BY calldate;