【问题标题】:Minimize SQL queries最小化 SQL 查询
【发布时间】:2016-07-01 11:08:18
【问题描述】:

我创建了一个 php 代码来列出患有此病的患者

1 封电子邮件 2-零未来治疗 3-等于或多于1个完成的治疗 4-最晚完成治疗日期等于从今天开始的 3 周前

问题是,我有超过 50,000 名患者,对于每个患者,查询上述情况需要很长时间。

有没有一种方法可以将 sql 查询合并为一个,而不是让每个患者都有 3 个或更多查询,从而产生大约 200k 个查询?

代码如下:

$today = date('Y-m-d');
$three_weeks_ago = date('Y-m-d', strtotime($today.'-3 weeks'));
$patients = $db->query("
SELECT 
    dg_patients_patients.id,
    dg_patients_patients.first_name,
    dg_patients_patients.last_name,
    dg_patients_patients.email,
    dg_clinics.clinic_name,
    dg_clinics.clinic_address,
    dg_clinics.clinic_phone 
FROM dg_patients_patients 
    LEFT JOIN dg_clinics ON dg_patients_patients.clinic_id = dg_clinics.id 
WHERE dg_patients_patients.email <> '' ORDER BY dg_patients_patients.first_name ASC ");

$now = date('Y-m-d H:i:s');

foreach ($patients as $row){

    $patientID = $row['id'];

    //Get Patient Future Treatments
    $check_future_treatments = $db->column("SELECT id FROM dg_patient_treatment_finance WHERE treatment_type = :a1 AND patient_id = :a2 ",array("a1"=>"1","a2"=>"$patientID"));
    $future_treatments = count($check_future_treatments);

    //Get Patient Finished Treatments
    $check_finished_treatments = $db->column("SELECT id FROM dg_patient_treatment_finance WHERE treatment_type = :a1 AND patient_id = :a2 ",array("a1"=>"2","a2"=>"$patientID"));
    $finished_treatments = count($check_finished_treatments);


    if($future_treatments == 0 && $finished_treatments > 0 ) {

        $latest_finished_treatment_date = $db->single("SELECT plan_date FROM dg_patient_treatment_finance WHERE patient_id = :pid ORDER BY plan_date DESC LIMIT 1 ", array("pid"=>"$patientID"));

        if($latest_finished_treatment_date == $three_weeks_ago){

            echo $patientID.'- '.$row['first_name'].' '.$row['last_name'].' - '.$row['email'].'<br>';

        }
    }

【问题讨论】:

  • 实际上您的条件 2,3 和 4 可能与最近的治疗是 3 周前相同。至少从语义的角度来看 - 我不知道您的 treatment_type 是如何处理的。你可以直接应用这个逻辑还是不允许它?
  • 如果treatment_type为1表示未来治疗,如果为2则表示治疗结束。
  • 在 db(行)上下文中,“未来治疗”不是由未来日期决定的,而是由分配的类型决定的,所以我可以想象 treatment_type=1 在上周或 3 周前拥有 plan_date。目前,您的查询忽略了这一点,并将它们视为“未来”,从而将此类患者从列表中删除。不知道它是故意的(尽管在语义上是矛盾的)还是有一些隐藏的约束阻止在 db 中有这样的行。

标签: php sql join


【解决方案1】:

您可以尝试对 dg_patient_treatment_finance 进行 LEFT JOIN,使用 GROUP BY 并将 SUM 与 CASE 语句结合使用。
同时计算MAX plan_date。

SELECT 
    p.id, p.first_name, p.last_name, p.email,
    c.clinic_name, c.clinic_address, c.clinic_phone,
    SUM(case when tf.treatment_type = 1 then 1 else 0 end) as total_treatment_type_1,
    SUM(case when tf.treatment_type = 2 then 1 else 0 end) as total_treatment_type_2,
    MAX(tf.plan_date) as max_plan_date
FROM dg_patients_patients p
LEFT JOIN dg_clinics c ON (p.clinic_id = c.id)
LEFT JOIN dg_patient_treatment_finance tf ON (p.id = tf.patient_id and tf.treatment_type IN (1,2))
WHERE p.email <> '' 
GROUP BY 
    p.id, p.first_name, p.last_name, p.email,
    c.clinic_name, c.clinic_address, c.clinic_phone
ORDER BY p.first_name, p.last_name

那么您还可以通过从计算的总和中获取内容来简化 $future_treatments 和 $finished_treatments 的计算。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-24
    相关资源
    最近更新 更多