Tuesday 4 September 2018

The use of LEFT JOIN does not work as expected

I have the following tables :

store_list
id store
1    m1
2    m2
3    m3

Contains store name by which each store name have its own table for sold items as follows :
s_m1_sales
id  item  qty  date
1    x1    5   16-5-2016
2    x2    6   16-5-2016
3    x3    1   16-5-2016

s_m2_sales
id  item  qty  date
1    x2    3   16-5-2016
2    x2    3   16-5-2016
3    x2    5   16-5-2016

and so on for the 3rd store...
And for the final Table :
store_items
id  item  qty  cat  sub
10  x1   15    lady  slip
11  x2   10    lady  shoe
12  x3   10    lady  shoe

Now I'm looking for a report to find how many items sold within certain date for a specific category (cat) AND GROUPED BY category. I need something too look like this :
cat   sub      M1   M2  M3   date
lady  slip     5    0   0     16-5-2016
lady  shoe     7    11  0     16-5-2016

My PHP code , I've used LEFT JOIN and output result as correctly :
//rest of code 

//Table created
echo "<table width=90% height=% align=center border=1 cellpadding=3 cellspacing=0>";
echo "<tr>
    <td align=center width=12%><b>Supplier</b></td>
    <td align=center width=12%><b>Category</b></td>
    <td align=center width=12%><b>Sub-Category</b></td>
";

foreach($allstore as $store => $value){
    echo "<td align=center width=5%><b><font color=green size=+1>".$value."</font></b></td>";
}

//$allstore is an array , by which values taken from user checkbox select
$allstore = $_POST['store'];

foreach($allstore as $store => $value){

    $query = "SELECT s_{$value}_sales.item_no,
            store_items.cat,
            store_items.supplier,
            store_items.sub,
            SUM(s_{$value}_sales.qty) AS a1
      FROM s_{$value}_sales
      LEFT JOIN store_items ON s_{$value}_sales.item_no = store_items.item_no
            AND store_items.cat = '".$_POST['cat']."'
            AND s_{$value}_sales.date BETWEEN '".$_POST['fdate']."' AND '".$_POST['tdate']."'
            AND store_items.store = '".$value."'
      GROUP by store_items.sub
    ";

    $result=  mysql_query($query);

    while($row = mysql_fetch_assoc($result)) {
        echo "<tr><td align=center width=12%>{$row['supplier']}</td>
        <td align=center width=12%>{$row['cat']}</td>
        <td align=center width=12%>{$row['sub']}</td>
        <td align=center>".$row['a1']."</td>
    ";
    }
}
echo "</tr></table>";
//rest of code..

As I mentioned earlier, the output is correct but what happens that it loops category and sub-categories multiple of times. I don't want that i want to list stores and its sum qty's in each column. How can i do it ?
The above PHP output as follows :
cat  sub   M1   M2   M3
lady slip  5
lady shoe  7
lady slip  0
lady shoe  11
lady slip  0
lady shoe  0


Why have a separate table for each stores' sales? You should easily be able to combine them all into a single table with a store id column. That would also help resolve your problem, which is that you are making queries in a loop for each store. With that approach you will never be able to compile data across stores into single rows without some post-processing in PHP.
Let me propose an alternate store_sales table structure like this:
id  store_id  item_id  qty  date
1      1      10       5   16-5-2016
2      1      11       6   16-5-2016
3      1      12       1   16-5-2016
4      2      11       3   16-5-2016
5      2      11       3   16-5-2016
6      2      11       5   16-5-2016
...

Note the addition of store_id field and the replace of the item field with item_id field (you should reference the appropriate foreign key here).
That allows you to simplify your query to this:
SELECT
    store_list.store AS store,
    store_items.cat AS cat,
    store_items.sub AS sub,
    SUM(store_sales.qty) AS qty
FROM store_list
LEFT JOIN store_sales
    ON store_list.id = store_sales.store_id
INNER JOIN store_items
    ON store_sales.item_id = store_items.id
WHERE store_sales.date BETWEEN ? AND ?
GROUP BY `store`, `cat`, `sub`
ORDER BY `store` ASC, `cat` ASC, `sub` ASC

That would give a result set like:
store  cat   sub   qty
m1     lady  slip  5
m1     lady  shoe  7
m2     lady  shoe  11
m3     null  null  0

It is trivial to read this inter a multi-dimensional array in PHP for display in whatever format you choose for the page. I don't see much value in trying query your data into a "pivot table" type of format you have shown, as this will just make the query more complex and less performant. This is possible to do using case statements in the select, but I didn't want to clutter to focus of my answer, which is to primarily get your database schema in order.

0 comments:

Post a Comment