我一直在努力处理以下情况:
第一种方法:
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
和styleID
。这将导致整个结果重复。我已经尝试过DISTINCT
和各种GROUP BY
,包括DISTINCT
和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>";
}
答案 0 :(得分:1)
您可以使用GROUP_CONCAT将结果缩小到两个维度,这样就不会仅因为填充样式下拉列表而获得重复的相册。 取而代之的是,您将样式合并在一起,并使用换行符使其变得漂亮。
您的查询最终看起来像这样:
SELECT
trackID,
vinylID,
side,
trackArtist,
trackTitle,
notes,
GROUP_CONCAT(mKeyID SEPARATOR '\n') as 'mKeyIDs',
GROUP_CONCAT(mKey SEPARATOR '\n') as 'mKeys',
Camelot,
GROUP_CONCAT(styleID SEPARATOR '\n') AS 'styleIDs',
GROUP_CONCAT(styleName SEPARATOR '\n') AS 'styleNames'
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
GROUP BY
vt.trackID
WHERE
vinylID = :vinylID
我在这里按轨道ID进行分组,因为这似乎是您用来确定某件商品是否重复的标准。从那里开始,我使用带有新行分隔符的GROUP_CONCAT在同一单元格中显示受此组影响的所有样式。您的PHP可以引用此单元格,并在换行符上爆炸以获取填充下拉列表所需的内容。
确保此查询首先直接在数据库上运行,以查看是否需要对其进行调整。
或者,如果您的MySQL版本支持JSON_ARRAYAGG,则可以使用它代替GROUP_CONCAT来完成功能上等效的行为,尽管更为简洁:
SELECT
trackID,
vinylID,
side,
trackArtist,
trackTitle,
notes,
JSON_ARRAYAGG(mKeyID) AS 'mKeyIDs',
JSON_ARRAYAGG(mKey) AS 'mKeys',
Camelot,
JSON_ARRAYAGG(styleID) AS 'styleIDs',
JSON_ARRAYAGG(styleName) AS 'styleNames'
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
GROUP BY
vt.trackID
WHERE
vinylID = :vinylID
然后在您的PHP中,您只需引用$row['styleIDs']
和$row['styleNames']
即可为“样式”下拉列表中使用的每个选项生成键=>值对。
对于音乐“键”下拉选项,请参考$row['mKeyID']
和$row['mKeys']
为“键”下拉菜单中使用的每个选项生成键=>值对。
更新:
我在本地进行了设置,并发现OP遇到了问题。我的查询很好。但是,当试图显示下拉列表时,OP的PHP循环逻辑遇到了一个错误。更具体地说,以下逻辑是错误的:
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>";
}
}
}
现在,我了解OP想要做什么,让我们重写整个混乱。我已经重构了代码。我也在本地进行了测试:
$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'
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
WHERE vt.vinylID = :vinylID
GROUP BY vt.trackID");
$tracksQuery->bindParam(':vinylID', $vinylID);
$tracksQuery->execute();
$tracks = $tracksQuery->fetchAll(\PDO::FETCH_ASSOC);
$allStylesQuery = $db->prepare("SELECT * FROM vinyl_styles ORDER BY styleID ASC");
$allStylesQuery->execute();
$styles = $allStylesQuery->fetchAll(PDO::FETCH_ASSOC);
$stylesSelector = "";
foreach($tracks as $track)
{
$stylesSelector .= "<select multiple=\"multiple\" class=\"form-control form-control-sm\" name=\"styleID[".$track['trackID']."][]\"><option> – </option>";
$trackStyleIDs = explode(',', $track['styleIDs']);
foreach($styles as $style)
{
$optionValue = $style['styleID'];
$optionText = $style['styleName'];
$optionSelected = in_array($optionValue, $trackStyleIDs) ? ' selected="selected"' : '';
$stylesSelector .= sprintf('<option value="%s"%s>%s</option>', $optionValue,$optionSelected,$optionText);
}
$stylesSelector .= "</select>";
}
答案 1 :(得分:0)
正如我在评论中所说,您必须分两步细分该过程。
分别存储样式之后,现在将有一个像这样的数组,
[
track_id_1 => [ style_id_1, style_id_2, ]
track_id_2 => [ style_id_x, style_id_y, ]
]
意思是如果您知道轨道ID和样式ID,则可以使用in_array
测试样式是否附加到当前轨道:
<?php
if (in_array($style_id, $styles_per_track[$track_id])) {
echo 'Style '.$style_id.' is attached to track '.$track_id;
}
以下是该解决方案的模型。
(请注意,我没有测试任何代码,这只是为了给您一个分离数据的想法)
<?php
// Step 1: Fetch all tracks w/out worrying about styles
$tracks_stmt = $db->prepare('SELECT * FROM vinyl_tracks vt WHERE vinylID=:vinylID');
$track_stmt->execute([':vinylID' => $vinylID, ]);
$tracks = $track_stmt->fetchAll(\PDO::FETCH_ASSOC);
// Step 2: Loop each track and store the styles accordingly
$styles_per_track = [];
$styles_per_track_stmt = $db->prepare('SELECT * FROM vinyl_tracks_styles vts WHERE trackId=:trackId')
foreach($tracks as $track) {
$vinyl_tracks_styles[$track['trackID']] = [];
$styles_per_track_stmt->execute($track['trackID']);
$temp = $styles_per_track_stmt->fetchAll(\PDO::FETCH_ASSOC);
foreach($temp as $style_per_track) $vinyl_tracks_styles[$track['trackID']] = $style_per_track['styleID'];
}
//fetch styles
/**
...
...
...
**/
foreach($tracks as $track) {
?>
<select name="track[<?=$track['trackID'];?>" multiple>
<?php
foreach($styles as $style) {
?>
<option value="<?= $style['styleID']; ?>" <?php if(in_array($style['styleID'], $styles_per_track[$track['trackID']])) { echo ' selected'; } ?>><?= $style['styleName']; ?></option>
<?php
}
?>
</select>
<?php
}
?>