我一直在努力解决以下案例:
第一种方法:
SELECT * FROM vinyl_tracks vt
INNER JOIN vinyl_keys vk ON vt.mKeyID = vk.mKeyID
INNER JOIN vinyl_tracks_styles vts ON vt.trackID = vts.trackID
INNER JOIN vinyl_styles vs ON vts.styleID = vs.styleID
WHERE vinylID = :vinylID
对于某些曲目,表格vts
将包含两种或多种样式(表格仅在单独的行中包含trackID
and styleID
。这会导致整个结果重复。我尝试过DISTINCT
,以及各种GROUP BY
,包括DISTINCT
and GROUP BY
。这确实返回一个每个轨道的结果,但第二个styleID
丢失了。
这是var_dump
没有任何查询的GROUP BY
:
array (size=4)
0 =>
array (size=10)
'trackID' => string '868' (length=3)
'vinylID' => string '249' (length=3)
'side' => string 'A' (length=1)
'trackArtist' => string '' (length=0)
'trackTitle' => string 'Waiting (John Creamer & Stephane K Remix)' (length=41)
'notes' => string '130 bpm' (length=7)
'mKeyID' => string '1' (length=1)
'mKey' => string 'A major' (length=7)
'Camelot' => string '11B' (length=3)
'styleID' => string '8' (length=1)
1 =>
array (size=10)
'trackID' => string '868' (length=3)
'vinylID' => string '249' (length=3)
'side' => string 'A' (length=1)
'trackArtist' => string '' (length=0)
'trackTitle' => string 'Waiting (John Creamer & Stephane K Remix)' (length=41)
'notes' => string '130 bpm' (length=7)
'mKeyID' => string '1' (length=1)
'mKey' => string 'A major' (length=7)
'Camelot' => string '11B' (length=3)
'styleID' => string '17' (length=2)
2 =>
array (size=10)
'trackID' => string '869' (length=3)
'vinylID' => string '249' (length=3)
'side' => string 'B' (length=1)
'trackArtist' => string '' (length=0)
'trackTitle' => string 'Waiting (Jay Welsh (Black Ice) Remix)' (length=37)
'notes' => string '135 bpm' (length=7)
'mKeyID' => string '1' (length=1)
'mKey' => string 'A major' (length=7)
'Camelot' => string '11B' (length=3)
'styleID' => string '17' (length=2)
3 =>
array (size=10)
'trackID' => string '869' (length=3)
'vinylID' => string '249' (length=3)
'side' => string 'B' (length=1)
'trackArtist' => string '' (length=0)
'trackTitle' => string 'Waiting (Jay Welsh (Black Ice) Remix)' (length=37)
'notes' => string '135 bpm' (length=7)
'mKeyID' => string '1' (length=1)
'mKey' => string 'A major' (length=7)
'Camelot' => string '11B' (length=3)
'styleID' => string '8' (length=1)
然后我运行另一个查询来获取所有样式,以便我可以填充多选下拉菜单。这是创建下拉列表和屏幕截图的循环的样子foreach
- 两个轨道,每个轨道都有两种样式,显示为四个轨道:
$allStylesQuery = $db->prepare("SELECT * FROM vinyl_styles ORDER BY styleID ASC");
$allStylesQuery->execute();
$styles = $allStylesQuery->fetchAll(PDO::FETCH_ASSOC);
$stylesSelector = "<select multiple=\"multiple\" class=\"form-control form-control-sm stylesSelector\" name=\"styleID[".$trow['trackID']."][]\"><option> – </option>";
foreach($styles as $style) {
if(isset($trow['styleID']) && ($trow['styleID'] == $style['styleID'])) {
$stylesSelector .= "<option selected=\"selected\" value=\"".$style['styleID']."\">".$style['styleName']."</option>";
}
else {
$stylesSelector .= "<option value=\"".$style['styleID']."\">".$style['styleName']."</option>";
}
}
$stylesSelector .= "</select>";
替代方法: 我也尝试使用两个查询来完成相同的操作:
SELECT * FROM vinyl_tracks vt
INNER JOIN vinyl_keys vk ON vt.mKeyID = vk.mKeyID
WHERE vinylID = :vinylID
然后,在foreach
循环内部从第一个查询中获取结果,查询如下:
SELECT * FROM vinyl_tracks_styles vts
RIGHT JOIN vinyl_styles vs ON vts.styleID = vs.styleID
WHERE vts.trackID = :trackID
这种替代方式会产生我想要的结果,例如:
array (size=2)
0 =>
array (size=3)
'trackID' => string '868' (length=3)
'styleID' => string '8' (length=1)
'styleName' => string 'progressive house' (length=17)
1 =>
array (size=3)
'trackID' => string '868' (length=3)
'styleID' => string '17' (length=2)
'styleName' => string 'progressive trance' (length=18)
为了在选择下拉列表中列出所有可能的样式,我需要再运行一个查询(WHERE
上面的条件会阻止显示所有样式名称和 ID,尽管RIGHT JOIN
我知道):
SELECT * FROM vinyl_styles ORDER BY styleID ASC
突出显示我发现的选择选项(样式)的唯一方法是将两个foreach
循环相互嵌套,这当然会再次导致重复的结果:
$trackStylesQuery = $db->prepare("SELECT * FROM vinyl_tracks_styles vts
RIGHT JOIN vinyl_styles vs ON vts.styleID = vs.styleID
WHERE vts.trackID = :trackID");
$trackStylesQuery->bindParam(':trackID', $trow['trackID'], PDO::PARAM_INT);
$trackStylesQuery->execute();
$trackStyles = $trackStylesQuery->fetchAll(PDO::FETCH_ASSOC);
//var_dump($trackStyles);
$allStylesQuery = $db->prepare("SELECT * FROM vinyl_styles ORDER BY styleID ASC");
$allStylesQuery->execute();
$styles = $allStylesQuery->fetchAll(PDO::FETCH_ASSOC);
$stylesSelector = "<select multiple=\"multiple\" class=\"form-control form-control-sm stylesSelector\" name=\"styleID[".$trow['trackID']."][]\"><option> – </option>";
foreach($styles as $style) {
foreach($trackStyles as $trackStyle) {
if(isset($trackStyle['styleID']) && ($trackStyle['styleID'] == $style['styleID'])) {
$stylesSelector .= "<option selected=\"selected\" value=\"".$style['styleID']."\">".$style['styleName']."</option>";
}
else {
$stylesSelector .= "<option value=\"".$style['styleID']."\">".$style['styleName']."</option>";
}
}
}
$stylesSelector .= "</select>";
如果我坚持上面的第一个查询变体,整行输入重复两次,所以对于这两个轨道,我得到四行。
我真的没有想法,请帮助。
更新
使用@Ultimater 建议的更少查询方法,我现在已经达到了我需要的所有详细信息的情况,唯一的问题是样式列表在样式下拉列表中重复,用于轨道具有的每种样式。如果一个曲目只添加了一种样式或没有添加样式,则没有问题。在下面发布我的完整代码:
$tracksQuery = $db->prepare("SELECT vt.trackID, vt.vinylID, vt.side, vt.trackArtist, vt.trackTitle, vt.notes, vt.mKeyID, vk.mKey, vk.Camelot,
GROUP_CONCAT(vts.styleID SEPARATOR ',') AS 'styleIDs',
GROUP_CONCAT(vs.styleName SEPARATOR ',') AS 'styleNames'
FROM vinyl_tracks vt
INNER JOIN vinyl_keys vk ON vt.mKeyID = vk.mKeyID
LEFT JOIN vinyl_tracks_styles vts ON vt.trackID = vts.trackID
LEFT JOIN vinyl_styles vs ON vts.styleID = vs.styleID
WHERE vt.vinylID = :vinylID
GROUP BY vt.trackID");
$tracksQuery->bindParam(':vinylID', $vinylID);
$tracksQuery->execute();
$tracks = $tracksQuery->fetchAll(\PDO::FETCH_ASSOC);
//var_dump($tracks);
// fetch all styles to use in the dropdown
$allStylesQuery = $db->prepare("SELECT * FROM vinyl_styles ORDER BY styleID ASC");
$allStylesQuery->execute();
$styles = $allStylesQuery->fetchAll(PDO::FETCH_ASSOC);
// build a dropdown menu for each of the tracks
// which contains all styles and where the current track's styles are selected
$stylesSelector = "";
foreach($tracks as $track) {
// start building the selector
$stylesSelector .= "<select multiple=\"multiple\" class=\"form-control form-control-sm\" name=\"styleID[".$track['trackID']."][]\"><option> – </option>";
// check if any styles have been added for this track
if(!empty($track['styleIDs'])) {
// check if StyleIDs and StyleNames results contain a comma
// which means more than one style has been added for that track
if((strpos($track['styleIDs'], ',')) && (strpos($track['styleNames'], ','))) {
// separate trackStyleIDs and trackStyleNames
$trackStyleIDs = explode(',', $track['styleIDs']);
$trackStyleNames = explode(',', $track['styleNames']);
// now combine them in one array where styleID is the key and styleName is the value
$styleIDs_and_Names = array_combine($trackStyleIDs, $trackStyleNames);
// for each of the styleID => styleName pairs in the array
// check against all available styles if selected
foreach($styleIDs_and_Names as $styleID => $styleName) {
// iterate over all available styles
foreach($styles as $style) {
// if there's a match, add "selected" to the option
if($styleID == $style['styleID']) {
$stylesSelector .= "<option selected=\"selected\" value=\"".$style['styleID']."\">".$style['styleName']."</option>";
}
else {
$stylesSelector .= "<option value=\"".$style['styleID']."\">".$style['styleName']."</option>";
}
}
}
}
// only one style has been added for this track
else {
// iterate over all available styles
foreach($styles as $style) {
// if there's a match, add "selected" to the option
if($track['styleIDs'] == $style['styleID']) {
$stylesSelector .= "<option selected=\"selected\" value=\"".$style['styleID']."\">".$style['styleName']."</option>";
}
else {
$stylesSelector .= "<option value=\"".$style['styleID']."\">".$style['styleName']."</option>";
}
}
}
}
// if no styles have been added for this track
else {
// iterate all available styles
foreach($styles as $style) {
$stylesSelector .= "<option value=\"".$style['styleID']."\">".$style['styleName']."</option>";
}
}
$stylesSelector .= "</select>";
}