2014-07-16 21 views
0

我正在渲染一個基於來自SQLite中的多個數據庫表的數據。如何改進這個SQL查詢(SQLite和PHP)

表:

  • 人員 - 包含所有用戶/工作人員,可以有證書
  • 證書---包含所有可用證書,用戶可以有
  • rel__staff_certificate ---包含連接證書(關係)給用戶

TABLE staff

`staff_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
`name` TEXT NOT NULL, 

certificates

`cert_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
`caption` TEXT NOT NULL, 
`description` TEXT 

rel__staff_certificate

`rel_id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, 
`staff_id` INTEGER, 
`cert_id` INTEGER, 
`cert_date` TEXT NOT NULL, 
`comments` TEXT 

因此,這裏的交易:

// Get all available certificates 
$sql_get_cert = "SELECT * FROM certificates ORDER BY cert_id ASC"; 

// Get all certificates for staff user 
$sql_get_staff_cert_rel = "SELECT * FROM rel__staff_certificate WHERE staff_id = :staff_id AND cert_id = :cert_id LIMIT 1"; 

// Prepare SQL queries... 
$get_cert_rel = $PDODB->prepare($sql_get_staff_cert_rel); 
$get_cert = $PDODB->prepare($sql_get_cert); 

// Get all certificates to array $certdata 
$get_cert->execute(); 
$certdata = $get_cert->fetchAll(); 

// Create the array where I want to push data to: 
$staffdata[$i] = array(
    $staff['staff_id'], // $staff() is populated earlier and works just fine 
    $staff['name'], 
    $ccdata['region'], // $ccdata() is populated earlier and works just fine 
    $ccdata['cc_code'] 
); 

// Loop through all available certificates in table ´certificates´ 
foreach ($certdata as $cert) { 
    // Bind values for the relation SQL now when we have them all 
    $get_cert_rel->bindValue(':staff_id', $staff['staff_id']); 
    $get_cert_rel->bindValue(':cert_id', $cert['cert_id']); 
    $get_cert_rel->execute(); 

    // Get the certification relation data to array $certreldata() 
    $certreldata = $get_cert_rel->fetch(); 

    // If a certificate date exists, then use that for our array which tells us that this staff has this certificate and was certified on this date 
    if (!empty($certreldata['cert_date'])) { 
     array_push($staffdata[$i], $certreldata['cert_date']); 
    } 
    // If no certificate date exsits, then just add value "N/A" as not available 
    else { 
     array_push($staffdata[$i], 'N/A'); 
    } 
} 

確定這樣完蛋了!它可以工作,但正如你所看到的,我正在向foreach()循環中的SQL服務器執行大量的SQL執行操作,我不相信這會很好,因爲它會消耗大量不必要的時間。

任何人都可以告訴我如何使用單個SQL查詢來做到這一點嗎?或者告訴我如何改進代碼,以其他方式進一步加快速度?

謝謝。

+3

如何使用連接? –

回答

0

您可以使用JOIN進行此類查詢。

使用LEFT JOIN使用第一個表(左)的私鑰和第二個(右)的外鍵加入這兩個表,而如果在第二個(右)表中沒有找到行,則用於右表將充滿NULL值:

SELECT c.* 
FROM certificates AS c 
LEFT JOIN rel__staff_certificate AS sc ON sc.cert_id = c.cert_id 
WHERE sc.staff_id = ? 
ORDER BY c.cert_id 

使用INNER JOIN連接兩個表相同的方式,在LEFT JOIN,但如果有一個左表在右表中的私有密鑰的條目,這些行被跳過:

SELECT c.* 
FROM certificates AS c 
INNER JOIN rel__staff_certificate AS sc ON sc.cert_id = c.cert_id 
WHERE sc.staff_id = ? 
ORDER BY c.cert_id 

更多關於加入可在文檔 - 基本JOIN結構和JOIN operators中找到。

+0

謝謝你的回答! – Nick

+0

歡迎您! – shadyyx

1

這是可以做到的加盟:

SELECT cert_date 
FROM certificates 
JOIN rel__staff_certificate USING (cert_id) 
WHERE staff_id = ? 
+0

謝謝你的幫助! – Nick

1

嘗試使用SQL連接。下面是給出了相關的信息的一個例子:

SELECT 
    staff.staff_id, 
    staff.name, 
    certificates.caption, 
    certificates.description, 
    rel__staff_certificate.cert_date, 
    rel__staff_certificate.comments 
FROM rel__staff_certificate staff 
INNER JOIN certificates ON certificates.cert_id = rel__staff_certificate.cert_id 
INNER JOIN staff ON staff.staff_id = rel__staff_certificate.staff_id 
WHERE staff.staff_id = ? 

如果你希望所有工作人員及其所有證書在一個查詢的WHERE聲明可能是可選的。

+0

謝謝你的回答! – Nick