How to count items in a table based on the main query? - php

Okay guys say I am currently doing this query:
SELECT `category_id`, `category_name`
FROM `database_categorys`
ORDER BY `category_name` ASC
Now I want to count all rows from a table called "database_items" where the item table's category id is equal to the current rows category id.
Some sort of join or nested query I am guessing but I cannot wrap my head around the correct syntax to do it.
So that when echoing it out I can do:
<category name> <total items in category number>

SELECT c.`category_id`, c.`category_name`, count(i.`category_id`)
FROM `database_categorys` c
LEFT OUTER JOIN `database_items` i on c.`category_id` = i.`category_id`
GROUP BY c.`category_id`, c.`category_name`
ORDER BY c.`category_name`

I would use subqueries like this:
SELECT
`category_id`, `category_name`,
(SELECT count(1) from database_items i where i.category_id = c.category_id)
FROM `database_categorys` c
ORDER BY `category_name` ASC

Related

Alternative of NOT EXISTS in MySQL as query is taking time to execute with NOT EXISTS

Dummy table:
id FileName DateLastSaved
1 Marium.doc 2015-01-01
2 Amna.doc 2016-01-01
3 Marium.doc 2016-01-01
I want the query to return such rows where FileName is unique in the whole table. Rows should be returned for particular date range.
Suppose date ranges are of 2016 only, so third row should not be returned as FileName is not unique.
The query that I have created is:
$presentquery="SELECT * FROM InitialLog i WHERE MDid='$MDid' AND
(DateLastSaved>='$firstdate' AND DateLastSaved<='$presentdate') AND NOT
EXISTS (SELECT id FROM InitialLog i2 WHERE i2.id<i.id AND i.FileName=i2.FileName )";
(Where $firstdate and $presentdate are 2 dates for date ranges)
The query is returning the accurate results but it's taking time to execute. Is there any other way that I can rewrite this query??
(I have table with many rows)
I put this query together and it returns the results very quickly.
Select *
FROM foo
Where (`datelastsaved` > '2015-12-31' && `datelastsaved` < '2017-01-01')
AND `filename` NOT IN (
Select `filename`
FROM foo
GROUP BY `filename`
HAVING COUNT(*) > 1);
The first part is your normal select statement with the where clauses to filter on the dates.
The second part is the NOT IN where the select statement finds all of the ones with duplicate filenames.
Select `filename` FROM foo GROUP BY `filename` HAVING COUNT(*) > 1)
You can get the same logic using a LEFT JOIN and looking for nulls, that is,
$presentquery = "SELECT DISTINCT i.* FROM InitialLog i
LEFT JOIN InitialLog i2 ON i2.id<i.id AND i.FileName=i2.FileName
WHERE i.MDid='$MDid'
AND i.DateLastSaved>='$firstdate'
AND i.DateLastSaved<='$presentdate'
AND i2.id IS NULL";
This way you are doing a single join rather than subquerying against each value in i.
It looks like you are trying to get the data associated with the first occurrence of each file name, this should work:
SELECT *
FROM InitialLog i
WHERE MDid='$MDid'
AND DateLastSaved>='$firstdate'
AND DateLastSaved<='$presentdate'
AND id IN (SELECT MIN(id) FROM InitialLog GROUP BY FileName)
;
Alternatively, you can do a JOIN with the same subquery instead:
SELECT i.*
FROM InitialLog AS i
INNER JOIN (SELECT MIN(id) AS id
FROM InitialLog
GROUP BY FileName
) AS firsts USING (id)
WHERE i.MDid='$MDid'
AND i.DateLastSaved>='$firstdate'
AND i.DateLastSaved<='$presentdate'
;

Selecting specific rows from table

I have the below table (in picture) which is kind of inventory table and shows how many items comes in and how many goes out from stock, and item_id is the foreign key from another table.
I want to select those records that has no out from the stock, in other word i want to select those records which are highlighted in green (in the picture).
Thanks.
Sorry for poor English
The Table
Try this:
Select * from `table` where id in (select id from `table`group by id having sum(out)=0);
for deleting those values use:
delete t1
from `your_table` as t1
join (select item_id from `your_table`group by item_id having sum(item_out)=0) t2 on t1.item_id = t2.item_id
Try this query.
SELECT * FROM 'table_name' where out=0;
You need to join the table to itself: SELECT t.* FROM <your_table> AS t LEFT JOIN <your_table> AS t1 ON t.item_id=t1.item_id WHERE t1.out>0 AND t1.item_id IS NULL

Mysql Query for fetching result if corresponding table has records

I want to fetch records from one table ,if corresponding tables has record.
I am using this query .
SELECT `category_name`, `id` as cat_id FROM categories WHERE (SELECT count(id)> 0 FROM `articles` where `category_id` = cat_id) ORDER by `category_name` ASC
it is throwing error unknow cat_id
Any idea. how to do this
Thankse
An inner join could do this
select
c.category_name,
c.id as cat_id FROM categories c
join articles a on a.category_id = c.id
order by c.category_name
For the performance make sure that the joining keys are indexed
I would suggest to have something as
alter table categories add index id_idx(id);
alter table categories add index category_name_idx(category_name);
alter table articles add index category_id_idx(category_id)

Unable to return results for MySQL query

My goal is to only show purchase orders that haven't received all their product yet.
I have a master table called test_po and two other tables test_po_bom, test_rog_bom. The test_po_bom and test_rog_bom tables are where I'm storing the list of products. test_po_bom is the list of products I've ordered, test_rog_bom is the list of products I've received.
Basically: loop purchase_orders WHERE products_received < products_ordered
Table Structure:
table `test_po`: `ID`, `vendor_ID`
table `test_po_bom`: `ID`, `po_ID`, `product_ID`, `quantity`
table `test_rog_bom`: `ID`, `po_ID`, `product_ID`, `quantity`
Code:
$SQL = "SELECT
*,
test_po.ID AS test_po_ID
FROM
test_po
LEFT JOIN test_po_bom ON test_po_bom.po_ID=test_po.ID
LEFT JOIN test_rog_bom ON test_rog_bom.po_ID=test_po.ID
WHERE
(SELECT SUM(quantity) FROM test_rog_bom WHERE po_ID=test_po.ID) < (SELECT SUM(quantity) FROM test_po_bom WHERE po_ID=test_po.ID)";
$result = mysql_query($SQL) or die(mysql_error());
while($row = mysql_fetch_array($result))
{
echo $row['test_po_ID'].'<br>';
}
It doesn't spit out anything, and I've tried many different variations but I just can't figure it out.
The problem appears to be with your query. Don't use * and instead specify the desired columns. The following solution uses aliases to help make your code more readable, especially with similar names. You will also notice HAVING instead of WHERE.
SELECT
p.ID as PO_ID
,p.VENDOR_ID
,pb.product_ID as PRODUCT_ID
,SUM(pb.quantity) as QUANTITY_ORDERED
,SUM(rb.quantity) as QUANTITY_RECEIVED
FROM test_po as p
LEFT JOIN test_po_bom as pb ON pb.po_ID = p.ID
LEFT JOIN test_rog_bom as rb ON rb.po_ID = p.ID
GROUP BY
p.ID
,p.VENDOR_ID
,pb.product_ID
HAVING SUM(rb.quantity) < SUM(pb.quantity)
THIS IS UNTESTED CODE. I apologize for posting untested code but I can't test it right now, and I think it demonstrates some things for you to try differently even if it's not exactly correct.
Try this:
select po.ID, po_bom.quant n_ordered, rog_bom.quant n_received
from test_po po
left join (select po_ID, sum(quantity) as quant from test_po_bom group by po_ID) po_bom
on po.ID = po_bom.po_ID
left join (select po_ID, sum(quantity) as quant from test_rog_bom group by po_ID) rog_bom
on po.ID = rog_bom.po_ID
where coalesce(rog_bom.quant, 0) < coalesce(po_bom.quant, 0);
This changes a few things from how you were doing them:
Uses table aliases to clearly specify which references refer to the same table row.
Uses group by to aggregate the sums by ID.
Uses coalesce to deal with situation where at least one of your tables (probably test_rog_bom) has no rows for an ID. I suspect this was actually the source of your problem in the first place.

MYSQL return rows with number of column relationships in another table

I have a table categories and table posts . I want to return categories that have more than 3 posts.
My query
SELECT `categories`.`category_title`, COUNT(posts.post_id) as total_posts
FROM (`categories`)
JOIN `posts` ON `posts`.`category_id` = `categories`.`category_id`
HAVING `total_posts` > 3
ORDER BY `categories`.`date_created` desc
it returns just 1 row.. What is the correct way to do this type of query without using 2 queries?
Your query is making use of a MySQL feature called "hidden columns" and you might not even know it. This is because your query is referencing elements, such as date_created, which should be aggregated but are not ("should" here means according to the SQL standard and most other databases).
The problem with your query is that it is missing the group by. An alternative way of writing this is with the aggregation in a subquery, before joining to category:
SELECT `categories`.`category_title`, total_posts
FROM `categories` JOIN
(select categoryid, COUNT(posts.post_id) as total_posts
from `posts`
group by categoryid
having count(*) > 3
) pc
ON `pc`.`category_id` = `categories`.`category_id`
ORDER BY `categories`.`date_created` desc
You need to group the items by category.
SELECT `categories`.`category_title`, COUNT(posts.post_id) as total_posts
FROM (`categories`)
JOIN `posts` ON `posts`.`category_id` = `categories`.`category_id`
GROUP BY `categories`.`category_id`
HAVING `total_posts` > 3
ORDER BY `categories`.`date_created` desc

Categories