Group by 在查询中的奇怪行为需要优化 [英] Strange Behaviour of Group by in Query which needs to be optimized

查看:26
本文介绍了Group by 在查询中的奇怪行为需要优化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

谁能帮我优化这个查询

选择`debit_side`.`account_code` CODE,GROUP_CONCAT(DISTINCT accounts.name) 作为借记账户,GROUP_CONCAT(debit_side.amount) 作为 DebitAmount,GROUP_CONCAT(transaction_info.voucher_date) 作为 DebitVoucherDate,(选择GROUP_CONCAT(DISTINCT 帐户名称)从(账户)LEFT JOIN debit_sideON accounts.code = debit_side.account_code左加入 credit_sideON debit_side.transaction_id_dr = credit_side.transaction_id_cr左加入交易信息ON transaction_info.transaction_id = credit_side.transaction_id_crGROUP BY credit_side.account_codeHAVING credit_side.account_code = `Code`) 作为 CreditAccount,(选择GROUP_CONCAT(credit_side.amount) 作为 CreditAmount从(账户)LEFT JOIN debit_sideON accounts.code = debit_side.account_code左加入 credit_sideON debit_side.transaction_id_dr = credit_side.transaction_id_cr左加入交易信息ON transaction_info.transaction_id = credit_side.transaction_id_crGROUP BY credit_side.account_codeHAVING credit_side.account_code = `Code`) 作为 CreditAmount,(选择GROUP_CONCAT(transaction_info.voucher_date) 作为 CreditVoucherDate从(账户)LEFT JOIN debit_sideON accounts.code = debit_side.account_code左加入 credit_sideON debit_side.transaction_id_dr = credit_side.transaction_id_cr左加入交易信息ON transaction_info.transaction_id = credit_side.transaction_id_crGROUP BY credit_side.account_codeHAVING credit_side.account_code = `Code`) AS CreditVoucherDate从(`帐户`)左连接`credit_side`ON `accounts`.`code` = `credit_side`.`account_code`左联接`debit_side`ON `debit_side`.`transaction_id_dr` = `credit_side`.`transaction_id_cr`左连接`transaction_info`ON `transaction_info`.`transaction_id` = `credit_side`.`transaction_id_cr`GROUP BY `debit_side`.`account_code`有`代码`不为空ORDER BY `debit_side`.`account_code` ASC

实际上,在此查询中,我正在尝试获取所有帐户的借方和贷方数据.您一定已经注意到子查询重复但选择不同的列.此查询正在获取完美的结果,但我希望对其进行优化.这是我的架构的链接

http://www.sqlfiddle.com/#!2/82274/6

以前我有这两个查询,我试图合并

选择debit_side.account_code DebitCode,group_concat(distinct accounts.name) 作为 DebitAccount,group_concat(debit_side.amount) 作为 DebitAmount,group_concat(transaction_info.voucher_date) 作为 DebitVoucherDate来自(`帐户`)左连接`credit_side`ON `accounts`.`code` = `credit_side`.`account_code`左联接`debit_side`ON `debit_side`.`transaction_id_dr` = `credit_side`.`transaction_id_cr`左连接`transaction_info`ON `transaction_info`.`transaction_id` = `credit_side`.`transaction_id_cr`GROUP BY `debit_side`.`account_code`ORDER BY `debit_side`.`account_code` ASC

选择credit_side.account_code CreditCode,group_concat(distinct accounts.name) 作为 CreditAccount,group_concat(credit_side.amount) 作为 CreditAmount,group_concat(transaction_info.voucher_date) 作为 CreditVoucherDate来自(`帐户`)左联接`debit_side`ON `accounts`.`code` = `debit_side`.`account_code`左连接`credit_side`ON `debit_side`.`transaction_id_dr` = `credit_side`.`transaction_id_cr`左连接`transaction_info`ON `transaction_info`.`transaction_id` = `credit_side`.`transaction_id_cr`GROUP BY `credit_side`.`account_code`ORDER BY `credit_side`.`account_code` ASC

我还想删除正在获取的空记录.注意:您还应该注意,在子查询中,我根据我的要求使用了一些不同的条件.

编辑

我已经解决了删除空记录的问题,但优化仍然存在.

新的编辑

这是我尝试使用半连接的方法

选择`lds`.`account_code` DebitCode,group_concat(distinct la.name) 作为 DebitAccount,group_concat(lds.amount) 作为 DebitAmount,group_concat(lti.voucher_date) 作为 DebitVoucherDate,`rcs`.`account_code` CreditCode,group_concat(distinct ra.name) 作为 CreditAccount,group_concat(rcs.amount) 作为 CreditAmount,group_concat(rti.voucher_date) 作为 CreditVoucherDateFROM 帐户为 laLEFT 以 ra 身份加入帐户ON ra.`code` = la.`code`LEFT JOIN `credit_side` 作为 lcsON `la`.`code` = `lcs`.`account_code`LEFT JOIN `debit_side` 作为 ldsON `lds`.`transaction_id_dr` = `lcs`.`transaction_id_cr`LEFT JOIN `transaction_info` 作为 ltiON `lti`.`transaction_id` = `lcs`.`transaction_id_cr`LEFT JOIN `debit_side` 作为 rdsON `ra`.`code` = `rds`.`account_code`左连接`credit_side` rcsON `rds`.`transaction_id_dr` = `rcs`.`transaction_id_cr`LEFT JOIN `transaction_info` 作为 rtiON `rti`.`transaction_id` = `rcs`.`transaction_id_cr`按信用代码"分组有 `CreditCode` 不为空ORDER BY `CreditCode` ASC

奇怪的是,如果我通过使用 DebitCode 来更改组并订购,它会为借方带来完美的记录,如果我使用 CreditCode 更改它,如果为贷方带来完美的记录.有没有办法克服这个问题或任何替代方案.

解决方案

我一直在研究你的架构和 SQL,但我不太明白你的逻辑.我所看到的:

  • 您有一组交易(准确地说是 9 个);
  • 对于每笔交易,您都有借方和贷方的详细信息;
  • 使用每一侧的account_code,您可以获得有关帐户的信息.

所以,对于初学者,我会采用这种方式并创建一个 VIEW,它将为您提供有关您的交易的所有必要信息.我在这里使用了 INNER 连接,因为我相信每笔交易必须同时具有借方和贷方,而每一方又应该有一个帐户:

CREATE VIEW all_transactions AS选择 ti.transaction_id tid, ti.voucher_no tvno, ti.voucher_date tvdt,ds.account_code dacc, ds.amount damt, da.name daname, da.type dat,cs.account_code cacc, cs.amount camt, ca.name caname, ca.type catFROM transaction_info ti加入 debit_side ds ON ds.transaction_id_dr = ti.transaction_id加入 credit_side cs ON cs.transaction_id_cr = ti.transaction_id加入账户 da ON da.code = ds.account_code加入账户 ca ON ca.code = cs.account_code;

现在,查看您的查询,您似乎正在尝试获取每个帐户代码的所有柜台操作的列表.我不确定这样做的目的是什么,但我会执行以下操作:

  • 选择了一个唯一帐户代码列表;
  • 为每个帐户代码创建了借方操作的汇总列表,其中此类代码位于贷方;
  • 为贷方操作创建了相同的汇总列表,其中此类帐户位于借方;
  • 并将每个帐户代码放在中间.

所以这样的事情可能会完成这项工作:

SELECT group_concat(dacc) "D-Accounts",group_concat(damt) "D-数量",group_concat(daname) "D 名称",group_concat(dvdt) "D-日期",代码名称,group_concat(cacc) "C 账户",group_concat(camt) "C-Amounts",group_concat(caname) "C 名称",group_concat(cvdt) "C-日期"从 (选择 atl.dacc、atl.damt、atl.daname、atl.tvdt dvdt、a.code、a.name、NULL cacc、NULL camt、NULL caname、NULL cvdtFROM 帐户LEFT JOIN all_transactions atl ON atl.cacc = a.code联合所有选择 NULL,NULL,NULL,NULL,a.code,a.name,atr.cacc、atr.camt、atr.caname、atr.tvdt cvdtFROM 帐户右连接 all_transactions atr ON atr.dacc = a.code) 全连接GROUP BY 代码、名称按代码订购;

在内部,我通过联合其他 2 个连接 LEFTRIGHT 来模拟 FULL OUTER 连接.外部执行所有分组.看看结果.

请注意,如果您想从结果中添加/删除列,您应该同时修改内部和外部查询.

我希望这是您一直在寻找的.

Can anyone one help me optimize this query

SELECT 
  `debit_side`.`account_code` CODE,
  GROUP_CONCAT(DISTINCT accounts.name) AS DebitAccount,
  GROUP_CONCAT(debit_side.amount) AS DebitAmount,
  GROUP_CONCAT(transaction_info.voucher_date) AS DebitVoucherDate,
  (SELECT 
    GROUP_CONCAT(DISTINCT accounts.name) 
  FROM
    (accounts) 
    LEFT JOIN debit_side 
      ON accounts.code = debit_side.account_code 
    LEFT JOIN credit_side 
      ON debit_side.transaction_id_dr = credit_side.transaction_id_cr 
    LEFT JOIN transaction_info 
      ON transaction_info.transaction_id = credit_side.transaction_id_cr 
  GROUP BY credit_side.account_code 
  HAVING credit_side.account_code = `Code`) AS CreditAccount,
  (SELECT 
    GROUP_CONCAT(credit_side.amount) AS CreditAmount 
  FROM
    (accounts) 
    LEFT JOIN debit_side 
      ON accounts.code = debit_side.account_code 
    LEFT JOIN credit_side 
      ON debit_side.transaction_id_dr = credit_side.transaction_id_cr 
    LEFT JOIN transaction_info 
      ON transaction_info.transaction_id = credit_side.transaction_id_cr 
  GROUP BY credit_side.account_code 
  HAVING credit_side.account_code = `Code`) AS CreditAmount,
  (SELECT 
    GROUP_CONCAT(transaction_info.voucher_date) AS CreditVoucherDate 
  FROM
    (accounts) 
    LEFT JOIN debit_side 
      ON accounts.code = debit_side.account_code 
    LEFT JOIN credit_side 
      ON debit_side.transaction_id_dr = credit_side.transaction_id_cr 
    LEFT JOIN transaction_info 
      ON transaction_info.transaction_id = credit_side.transaction_id_cr 
  GROUP BY credit_side.account_code 
  HAVING credit_side.account_code = `Code`) AS CreditVoucherDate 
FROM
  (`accounts`) 
  LEFT JOIN `credit_side` 
    ON `accounts`.`code` = `credit_side`.`account_code` 
  LEFT JOIN `debit_side` 
    ON `debit_side`.`transaction_id_dr` = `credit_side`.`transaction_id_cr` 
  LEFT JOIN `transaction_info` 
    ON `transaction_info`.`transaction_id` = `credit_side`.`transaction_id_cr` 
GROUP BY `debit_side`.`account_code` 
HAVING `Code` IS NOT NULL 
ORDER BY `debit_side`.`account_code` ASC 

Actually in this query i am trying to get data for debit side and credit side for all accounts. You must have noticed that sub queries are repeated but selecting different columns. This query is fetching perfect results but i want it to be optimized. Here is the link to my schema

http://www.sqlfiddle.com/#!2/82274/6

Previously i had these two queries which i tried to combine

SELECT
  debit_side.account_code    DebitCode,
  group_concat(distinct accounts.name) as DebitAccount,
  group_concat(debit_side.amount) as DebitAmount,
  group_concat(transaction_info.voucher_date) as DebitVoucherDate
FROM (`accounts`)
  LEFT JOIN `credit_side`
    ON `accounts`.`code` = `credit_side`.`account_code`
  LEFT JOIN `debit_side`
    ON `debit_side`.`transaction_id_dr` = `credit_side`.`transaction_id_cr`
  LEFT JOIN `transaction_info`
    ON `transaction_info`.`transaction_id` = `credit_side`.`transaction_id_cr`
GROUP BY `debit_side`.`account_code`
ORDER BY `debit_side`.`account_code` ASC

And

SELECT
  credit_side.account_code    CreditCode,
  group_concat(distinct accounts.name) as CreditAccount,
  group_concat(credit_side.amount) as CreditAmount,
  group_concat(transaction_info.voucher_date) as CreditVoucherDate
FROM (`accounts`)
  LEFT JOIN `debit_side`
    ON `accounts`.`code` = `debit_side`.`account_code`
  LEFT JOIN `credit_side`
    ON `debit_side`.`transaction_id_dr` = `credit_side`.`transaction_id_cr`
  LEFT JOIN `transaction_info`
    ON `transaction_info`.`transaction_id` = `credit_side`.`transaction_id_cr`
GROUP BY `credit_side`.`account_code`
ORDER BY `credit_side`.`account_code` ASC

Also i want to remove null record which is being fetched. Note : You should also note that in the sub queries i am using a little bit different conditions which are resulting according to my requirements.

EDITS

I have covercome the problem to remove the null record but optimization is left still.

NEW EDITS

Here is what i tried with semi join

SELECT
  `lds`.`account_code`    DebitCode,
  group_concat(distinct la.name) as DebitAccount,
  group_concat(lds.amount) as DebitAmount,
  group_concat(lti.voucher_date) as DebitVoucherDate,
  `rcs`.`account_code`    CreditCode,
  group_concat(distinct ra.name) as CreditAccount,
  group_concat(rcs.amount) as CreditAmount,
  group_concat(rti.voucher_date) as CreditVoucherDate
FROM accounts as la
  LEFT join accounts as ra
    ON ra.`code` = la.`code`
  LEFT JOIN `credit_side` as lcs
    ON `la`.`code` = `lcs`.`account_code`
  LEFT JOIN `debit_side` as lds
    ON `lds`.`transaction_id_dr` = `lcs`.`transaction_id_cr`
  LEFT JOIN `transaction_info` as lti
    ON `lti`.`transaction_id` = `lcs`.`transaction_id_cr`
  LEFT JOIN `debit_side` as rds
    ON `ra`.`code` = `rds`.`account_code`
  LEFT JOIN `credit_side` rcs
    ON `rds`.`transaction_id_dr` = `rcs`.`transaction_id_cr`
  LEFT JOIN `transaction_info` as rti
    ON `rti`.`transaction_id` = `rcs`.`transaction_id_cr`
GROUP BY `CreditCode`
HAVING `CreditCode` IS NOT NULL
ORDER BY `CreditCode` ASC

The strange thing is that if i change group by having and order by with DebitCode it bring perfect records for debit side and if i change this with CreditCode if brings perfect records for credit side. Is there any way to overcome this problem or any alternative.

解决方案

I've been looking into your schema and SQL for a while and I don't quite understand your logic. Things as I see them:

  • you have a set of transactions (9 to be precise);
  • for each transaction you have details on the debit and credit sides;
  • using the account_code on each side, you can obtain info about accounts.

So, I would go this way for starters and created a VIEW, that would provide you with all the necessary information bout your transactions. I have used INNER joins here, as I believe each transaction must have both, debit and credit sides, and each side, in turn, should have an account:

CREATE VIEW all_transactions AS
SELECT ti.transaction_id tid, ti.voucher_no tvno, ti.voucher_date tvdt,
       ds.account_code dacc, ds.amount damt, da.name daname, da.type dat,
       cs.account_code cacc, cs.amount camt, ca.name caname, ca.type cat
  FROM transaction_info ti
  JOIN debit_side ds ON ds.transaction_id_dr = ti.transaction_id
  JOIN credit_side cs ON cs.transaction_id_cr = ti.transaction_id
  JOIN accounts da ON da.code = ds.account_code
  JOIN accounts ca ON ca.code = cs.account_code;

Now, looking at your queries, it seems that you're trying to get a list of all counter-side operations for each account code. I'm not sure what's the purpose of this, but I would do the following:

  • selected a list of unique account codes;
  • created an aggregated list of debit-side operations for each account code, where such code was on the credit side;
  • created same aggregated list for credit-side operations, where such account was on debit side;
  • and put each account code in the middle.

So something like this might do the job:

SELECT group_concat(dacc) "D-Accounts",
       group_concat(damt) "D-Amounts",
       group_concat(daname) "D-Names",
       group_concat(dvdt) "D-Dates",
       code, name,
       group_concat(cacc) "C-Accounts",
       group_concat(camt) "C-Amounts",
       group_concat(caname) "C-Names",
       group_concat(cvdt) "C-Dates"
  FROM (
    SELECT atl.dacc, atl.damt, atl.daname, atl.tvdt dvdt,
           a.code, a.name, NULL cacc, NULL camt, NULL caname, NULL cvdt
      FROM accounts a
      LEFT JOIN all_transactions atl ON atl.cacc = a.code
    UNION ALL
    SELECT NULL, NULL, NULL, NULL, a.code, a.name,
           atr.cacc, atr.camt, atr.caname, atr.tvdt cvdt
      FROM accounts a
      RIGHT JOIN all_transactions atr ON atr.dacc = a.code
  ) full_join
 GROUP BY code, name
 ORDER BY code;

In the inner part I'm simulating FULL OUTER join by uniting 2 other joins, LEFT and RIGHT ones. And the outer part performs all the groupings. Take a look at the result.

Note, that if you'd like to add/remove columns from the result, you should modify both, inner and outer queries.

I hope this is what you've been looking for.

这篇关于Group by 在查询中的奇怪行为需要优化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆