Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/82.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
Sql 用于从3个表检索数据的查询_Sql_Oracle_Plsql - Fatal编程技术网

Sql 用于从3个表检索数据的查询

Sql 用于从3个表检索数据的查询,sql,oracle,plsql,Sql,Oracle,Plsql,我是SQL的新手,我对查询有疑问 我有三张桌子: 具有cons\u id\u no、key\u id字段的消费者 bm_bill,包含关键字id、票据id号、应付金额、票据日期字段 (它将包含消费者的所有账单金额和日期) mreceipt,其中包含字段key\u id、收据号、支付金额、罚款、支付日期(It) 将包含消费者的所有付款详细信息) consumer表与bm_bill和mreceipt具有一对多关系。 我想根据消费者的cons_id_no创建消费者的分类账信息。它应该 包含其证件号、钥

我是SQL的新手,我对查询有疑问

我有三张桌子:

  • 具有cons\u id\u no、key\u id字段的消费者
  • bm_bill,包含关键字id、票据id号、应付金额、票据日期字段 (它将包含消费者的所有账单金额和日期)
  • mreceipt,其中包含字段key\u id、收据号、支付金额、罚款、支付日期(It) 将包含消费者的所有付款详细信息)
  • consumer表与bm_bill和mreceipt具有一对多关系。 我想根据消费者的cons_id_no创建消费者的分类账信息。它应该 包含其证件号、钥匙号、票据号(最新)、票据日期(最新)、应付金额(最新)、收据号(最新)、已付金额(最新)、罚款(最新)、付款日期(最新) 为此,我创建了以下查询

    SELECT 
       c.key_id,
       c.cons_id_no consumerid, 
       b.bill_id_no billno,
       TO_CHAR(b.bill_date,'dd-Mon-YYYY') billdate,
       b.amt_payable,
       m.receipt_no receiptno, 
       TO_CHAR(m.pay_date,'dd-Mon-YYYY') paydate,
       m.amt_paid+m.fine amountpaid 
    FROM 
       consumer c 
    
       LEFT OUTER JOIN (SELECT key_id, MAX(bill_date) AS maxDate FROM bm_bill GROUP BY key_id) maxBillDate 
       ON (maxBillDate.key_id = c.key_id)
    
       LEFT OUTER JOIN bm_bill b 
       ON (b.key_id = c.key_id AND b.bill_date = maxBillDate.maxDate) 
    
       LEFT OUTER JOIN (SELECT key_id, MAX(pay_date) AS maxPayDate FROM mreceipt GROUP BY key_id) maxMReceipt 
       ON (maxMReceipt.key_id = c.key_id)
    
       LEFT OUTER JOIN mreceipt m 
       ON (m.key_id = c.key_id AND m.pay_date = maxMReceipt.maxPayDate)
    
    WHERE 
       c.cons_id_no='?';
    
    我执行了这个查询,它给了我想要的结果。然后我注意到查询太慢,并发现在我的解决方案中,我有:

    SELECT key_id, max(bill_date) AS maxDate FROM bm_bill GROUP BY key_id
    
    这是从bm_账单中检索所有密钥id和账单日期,在bm_账单中,我只需要特定密钥id的信息。最重要的是,我的解决方案中还有一个类似的查询


    因此,我的问题是:有没有更好的方法来做到这一点?

    1-我建议您使用
    命令
    使用
    DESC
    ,并使用
    TOP
    函数而不是
    MAX
    ,对数据进行
    分组
    ;另外,我将使用
    中的X(…)
    ,而不是
    左连接

    2-我不知道你的数据有多大,但如果你有上千万行,那么将分组结果存储在临时索引表中可能会缩短处理时间


    3-您需要多长时间运行此查询(新鲜度级别)也是相关的:如果您不需要过去几分钟的最新结果(而是当天的结果),那么一定要使用临时存储,您可以将其用于当天的所有查询。

    您说过,按原样查询会提供所需的结果。如果是这样的话,请考虑以下内容:

    您正在加入一个派生表(maxBillDate),其目的是什么?您没有将联接用作筛选器或表中的任何字段。所以…去掉它,重新执行查询,你应该看到没有它你会得到相同的结果

    …与派生表相同的存储:maxReceipt


    从这里开始,扔掉不必要的行李,看看你是怎么想的。

    你要加入两个表格(bm_bill和mreceipt)中的每一个两次。我要尝试的第一件事是更改您的查询,以避免双重联接,并查看它是否有区别,例如:

    SELECT 
       c.key_id,
       c.cons_id_no consumerid, 
       b.bill_id_no billno,
       TO_CHAR(b.bill_date,'dd-Mon-YYYY') billdate,
       b.amt_payable,
       m.receipt_no receiptno, 
       TO_CHAR(m.pay_date,'dd-Mon-YYYY') paydate,
       m.amt_paid+m.fine amountpaid 
    FROM 
       consumer c 
    
       LEFT JOIN (SELECT key_id,
       bill_id_no, bill_date,amt_payable,receipt_no receiptno , 
       ROW_NUMBER() OVER (PARTITION BY key_id ORDER BY bill_date DESC) as rn
       FROM bm_bill)b ON (b.key_id = c.key_id and b.rn =1)
    
    
       LEFT JOIN (SELECT key_id,
       pay_date , amt_paid, amt_paid, fine, 
       ROW_NUMBER() OVER (PARTITION BY key_id ORDER BY pay_date DESC) as rn
       FROM mreceipt) m ON (m.key_id = c.key_id and m.rn =1)
    
    
    WHERE 
       c.cons_id_no='?';
    

    如果效果不好,您可以使用Oracle“alternative”替代SQLServer
    OUTER APPLY
    ——创建两个函数,分别返回
    MAX(账单日期)
    MAX(付款日期)
    ,然后加入它们。

    好问题!这是一个棘手的问题,因为它需要像
    行数
    这样的分析函数,但这两个外部连接使事情变得复杂<代码>密级
    成功了。以下是我的想法:

    select * from (
      select
        c.key_id,
        c.cons_id_no consumerid,
        to_char(m.pay_date, 'dd-Mon-YYYY') paydate,
        m.receipt_no receiptno,
        m.amt_paid+m.fine amountpaid,
        dense_rank() over
          (order by m.pay_date desc nulls last) as paydaterank,
        to_char(b.bill_date, 'dd-Mon-YYYY') billdate,
        b.bill_id_no billno,
        b.amt_payable,
        dense_rank() over
          (order by b.bill_date desc nulls last) as billdaterank
     from customer c
     left outer join mreceipt m on c.key_id = m.key_id
     left outer join bm_bill b on c.key_id = b.key_id
     where c.cons_id_no = '?'
    )
    where paydaterank = 1 and billdaterank = 1
    
    我在以下条件下进行了测试:

  • bm_bill有多个相关行,mreceipt没有相关行
  • mreceipt有多个相关行,bm_bill没有行
  • bm_bill和mreceipt有相关行
  • 在每一种情况下,它都是有效的,但是像这样彻底的重写,您将需要进行更多的测试


    还要注意的是,为了解决这个问题,我重点关注了日期和ID,然后在后面添加了所有其他列。检查列列表中是否有键入错误或遗漏-我在键入所有内容后进行了快速检查,但可能遗漏了一些内容。

    @@hadinbe Oracle中没有TOP函数-检查问题标记。订购通常会降低性能…@Art:谢谢您的反馈!我不知道Oracle没有此功能。我可能不正确,但我在consumer和bm_bill表之间有一对多关系,在mreceipt表中也有一对多关系。我需要基于max(账单日期)和max(付款日期)的数据,这就是我添加它的原因。@kaushik——好的,但我的意思是,你没有使用它。因此,如果您需要它,那么您需要将其中的字段添加到SELECT子句中。您不是从bm_bill和mreceipt中检索所有数据吗?@kaushik:是的,但每个数据只检索一次(而不是原始查询中的两次)。今天,我学习了left EXTER join和partition by。使用这些东西,我也得到了你提出的同样的问题。我们可以在派生表中使用“c.key\u id”吗?然后我可以将检索到的行数减少到最小。@kaushik:我相信您不能直接这样做(据我所知,Oracle不直接支持SQLServer
    OUTER APPLY
    ),但您可以使
    left join
    返回对象类型的函数的每个结果都与之相关,使用你的提示。