ورود

View Full Version : سوال: ارتباط یک به چند دو جدول



Jason.Bourne
یک شنبه 05 خرداد 1392, 12:20 عصر
2 تا جدول به نام news و image دارم.
این دو با هم ارتباط یک به چند دارند (برای هر رکورد از جدول news ممکنه چند image در جدول دوم باشد).

من نیاز دارم که لیست اخبار به همراه تصاویر هر خبر را داشته باشم.
بنابراین به ازای هر خبر در جدول new یک select میزنم تا تصاویر تک تک اخبار را بدست بیارم.
این راه اصلا جالب نیست (تعداد select ها زیاد میشن).
چطوری میتونم با یک query به لیست اخبار در جدول news و تصاویر مربوط به هر خبر در جدول image دست پیدا کنم؟

امیـرحسین
یک شنبه 05 خرداد 1392, 13:02 عصر
اگه با یه کوئری میخواد، اطلاعات خبر هم تکرار میشه. حجم اطلاعات بیشتر میشه ولی یه کوئری همه رو میاره. مثلا:
SELECT news.id, news.title, images.id AS image, images.path
FROM news
LEFT JOIN images ON images.news = news.id
WHERE 1
الان اگه مثلا خبر ۱ چهار تا عکس داشته باشه، title و id رو چهار بار داریم.

روش دیگه UNION ALL هست که مشکل بالا رو نداره ولی یکم کثیفه...

Jason.Bourne
یک شنبه 05 خرداد 1392, 13:23 عصر
اگه با یه کوئری میخواد، اطلاعات خبر هم تکرار میشه. حجم اطلاعات بیشتر میشه ولی یه کوئری همه رو میاره. مثلا:
SELECT news.id, news.title, images.id AS image, images.path
FROM news
LEFT JOIN images ON images.news = news.id
WHERE 1
الان اگه مثلا خبر ۱ چهار تا عکس داشته باشه، title و id رو چهار بار داریم.

روش دیگه UNION ALL هست که مشکل بالا رو نداره ولی یکم کثیفه...

حقیقتش با Join انجامش داده بودم. اما مشکلم همون تکرار اطلاعات اخبار بودش.

با UNION ALL چطور میشه انجامش داد.

امیـرحسین
یک شنبه 05 خرداد 1392, 17:54 عصر
تو UNION ALL باید تعداد و نام ستون‌ها یکی باشه. برای همین باید لیست فیلدها رو مثل هم کنید:
(
SELECT
id,
title,
summary,
NULL AS path,
TRUE AS news
FROM news
WHERE 1
) UNION ALL (
SELECT
id,
name AS title,
NULL AS summary,
path,
news # news ID
FROM news
WHERE 1
)
اینجا مثلا برای SELECT دوم باید path برگردونم ولی تو SELECT اول ندارمش ولی چون ستون‌ها باید یکی باشن پس با NULL میسازمش.
اینم مثلا روش پردازشش تو PHP و PDO:

$select = $pdo->query($sql);
while ($row = $select->fetch(PDO::FETCH_ASSOC)) {
if ($row['news'] === true) { // "===" not "==:
// This is a `news` row
} else {
// This is a `images` row
}
}
روش کثیفیه. پیشنهاد میکنم ازش استفاده نکنید. من محض اطلاع گفتم.
اگر این SELECTها واستون هزینه داره میتونید سمت Stored Procedure هم برید.

امیـرحسین
یک شنبه 05 خرداد 1392, 18:03 عصر
یه روش دیگه هم هست. اینکه با یه SELECT لیست اخبار رو بگیرید. حین fetch آیدی‌هاشون رو نگه دارید و با یه SELECT دیگه همه‌ی تصاویر همه‌ی خبرها رو بگیرید.

$ids = '';
$news = array();
$select = $pdo->query('SELECT * FROM news WHERE 1');
while ($row = $select->fetch(PDO::FETCH_ASSOC)) {
$news[ $row['id'] ] = $row;
$ids .= ',' . $row['id'];
}

if (!empty($ids)) {
$select = $pdo->query('SELECT * FROM images WHERE news IN(' . substr($ids, 1) . ')');
while ($row = $select->fetch(PDO::FETCH_ASSOC)) {
$news[ $row['news'] ]['images'][ $row['id'] ] = $row;
}
}
echo '<pre>' . print_r($news, true);
/*
Array
(
[1] => Array
(
[id] => 1
[title] => A
[summary] => aaaa.
[images] => Array
(
[1] => Array
(
[id] => 1
[name] => nme
[path] => a/b/c/d.pdf
)

[2] => Array
(
[id] => 2
[name] => eee
[path] => a/b/c/g.jpg
)

)

)

[2] => Array
(
[id] => 2
[title] => B
[summary] => bbbb.
[images] => Array
(
[3] => Array
(
[id] => 1
[name] => nme
[path] => a/b/c/d.pdf
)

)

)

[3] => Array
(
[id] => 3
[title] => C
[summary] => ccc.
[images] => Array
(
)

)

)
*/
که این میشه کلا دو تا کوئری ولی کدهای اپلیکیشن رو بیشتر میکنه.
این روشها ابتکاری هستن و بسته به سیستمتون میتونن خوب و بد باشن.