MySQL How to include in where two clause? - php

SELECT
cms_module_ladu_batch.id AS batch_id,
name, t1, cms_module_ladu_batch.date_changed AS date_ch,
t13, t2, t3, t4, bkuup, date_modified, date_created,
kogused.aadress AS aadress,
kogused.kogus AS kogus,
SUM(kogused.kogus) AS total
FROM
cms_module_ladu_batch
LEFT JOIN kogused
ON cms_module_ladu_batch.id = kogused.bid
WHERE
t2!='Sildid'
GROUP BY
batch_id
Thats the MySQL code - the problem is following. I need to exclude rows where total is 0 and date_ch older than one month (date_cd format is "2011-01-01 00:00:00").
is it possible?
http://jsfiddle.net/tiitremmel/2mvrr/1/ - jsfiddle sample - first table is like mysql result is default and the second table is how the result should look.

Add the date condition into the WHERE-statement and the exclusion of your SUM as a
HAVING-statement. It should then look like this:
SELECT cms_module_ladu_batch.id AS batch_id,
cms_module_ladu_batch.date_changed AS date_ch,
kogused.kogus AS kogus,
SUM(kogused.kogus) AS total
FROM cms_module_ladu_batch
LEFT JOIN kogused ON cms_module_ladu_batch.id = kogused.bid
WHERE t2 != 'Sildid'
AND (
(
cms_module_ladu_batch.date_changed < DATE_SUB(NOW(), INTERVAL 1 MONTH)
AND SUM(kogused.kogus) > 0
)
OR
cms_module_ladu_batch.date_changed > DATE_SUB(NOW(), INTERVAL 1 MONTH)
)
GROUP BY batch_id;
Alternatively... use a UNION-Statement to glue two SELECTS together.
SELECT cms_module_ladu_batch.id AS batch_id,
cms_module_ladu_batch.date_changed AS date_ch,
kogused.kogus AS kogus,
SUM(kogused.kogus) AS total
FROM cms_module_ladu_batch
LEFT JOIN kogused ON cms_module_ladu_batch.id = kogused.bid
WHERE t2 != 'Sildid'
AND cms_module_ladu_batch.date_changed < DATE_SUB(NOW(), INTERVAL 1 MONTH)
GROUP BY batch_id
HAVING total > 0
UNION
SELECT cms_module_ladu_batch.id AS batch_id,
cms_module_ladu_batch.date_changed AS date_ch,
kogused.kogus AS kogus,
SUM(kogused.kogus) AS total
FROM cms_module_ladu_batch
LEFT JOIN kogused ON cms_module_ladu_batch.id = kogused.bid
WHERE t2 != 'Sildid'
AND cms_module_ladu_batch.date_changed > DATE_SUB(NOW(), INTERVAL 1 MONTH)
GROUP BY batch_id;
Try both, see what fits best for your solution.

SELECT
cms_module_ladu_batch.id AS batch_id,
name, t1, cms_module_ladu_batch.date_changed AS date_ch,
t13, t2, t3, t4, bkuup, date_modified, date_created,
kogused.aadress AS aadress,
kogused.kogus AS kogus,
SUM(kogused.kogus) AS total
FROM
cms_module_ladu_batch
LEFT JOIN kogused
ON cms_module_ladu_batch.id = kogused.bid
WHERE
t2!='Sildid' AND
date_ch < date_sub(now(), interval 1 month)
GROUP BY
batch_id
HAVING
SUM(kogused.kogus) <> 0

To filter outside the GROUP BY clause you can use the HAVING keyword.
http://dev.mysql.com/doc/refman/5.5/en/select.html

SELECT cms_module_ladu_batch.id AS batch_id,
cms_module_ladu_batch.date_changed AS date_ch,
kogused.kogus AS kogus,
SUM(kogused.kogus) AS total
FROM cms_module_ladu_batch
LEFT JOIN kogused ON cms_module_ladu_batch.id = kogused.bid
WHERE t2 != 'Sildid'
GROUP BY batch_id
HAVING (
(
cms_module_ladu_batch.date_changed < DATE_SUB(NOW(), INTERVAL 1 MONTH)
AND SUM(kogused.kogus) > 0
)
OR
cms_module_ladu_batch.date_changed > DATE_SUB(NOW(), INTERVAL 1 MONTH)
);
This were the final code that worked for me. Great thanks to all, but greatest to Bjoern - your idea of code helped me a lot!

Just add at the bottom:
HAVING (total<>0) AND (date_cd>=ADDDATE(CURDATE(), INTERVAL -1 MONTH))
Other reply (see comments):
HAVING (total<>0) OR (date_cd>=ADDDATE(CURDATE(), INTERVAL -1 MONTH))

Related

MySQLi Query 2 tables based on count form one table over 30 days

I am having a trouble with a query.
I need to collect 2 companies from trade_directory where they have status 1 and match 3 categories.
I want to select the 2 companies on the least view first basis counted from company_views within the last 30 days.
SELECT
b.id, b.v_date, b.c_id COUNT(b.c_id) AS v_count
AND b.v_date >= DATE_ADD(NOW(), INTERVAL - 30 DAY)
FROM
company_views b
LEFT JOIN trade_directory v ON v.id = b.c_id
WHERE
v.cat1 = 'cat'
AND v.cat2 = 'rat'
AND v.cat3 = 'hat'
AND v.status = '1'
GROUP BY
b.c_id
ORDER BY
v_count ASC
LIMIT 2
Thanks
Chris
You're using AND operator in SELECT instead of WHERE
AND b.v_date >= DATE_ADD(NOW(), INTERVAL - 30 DAY)
can your try this code
SELECT
b.id, b.v_date, b.c_id COUNT(b.c_id) AS v_count
FROM
company_views b
LEFT JOIN trade_directory v ON v.id = b.c_id
WHERE
v.cat1 = 'cat'
AND v.cat2 = 'rat'
AND v.cat3 = 'hat'
AND v.status = '1'
AND b.v_date >= DATE_ADD(NOW(), INTERVAL - 30 DAY)
GROUP BY
b.c_id
ORDER BY
v_count ASC
LIMIT 2
I changed my approach (using different tables but here it what is working but it is really really slow)
SELECT o.*, COUNT(e.c_id) AS b_count
FROM cat3_entries o
LEFT JOIN company_views e ON e.c_id = o.c_id
AND e.v_date >= DATE_ADD(NOW(), INTERVAL - 30 DAY)
WHERE
o.c3_id = '81'
GROUP BY
o.c_id
ORDER BY
b_count ASC
LIMIT
3;
If I could resolve the speed issue this one would be great.

Select results from table1 based on entries on table2

I have 2 tables;
banner_views (id, b_id, b_date)- this record a banner view every time it gets displayed
banners_dynamic (id, status, static_iname, static_keywords, static_url, static_alt, static_type, static_image, b_views, b_clicks) - stores the banner data
I would like to select 3 banners_dynamic results which have had the least views in the last 7 days.
I did put somethign together (see below) but I realised it was grabbing the total views for all banner rather than uniquely by id.
SELECT *,
(SELECT COUNT(*) FROM banner_views v WHERE v.b_date >= DATE(NOW()) - INTERVAL 7 DAY) as post_count
FROM banners_dynamic b
WHERE static_keywords LIKE '%test%' AND b.status='1' AND b.static_type='1'
ORDER BY post_count ASC LIMIT 3
Can anyone point me in the correct direction?
You must join both banners_dynamic table and your subquery with corresponding banner IDs:
SELECT
b.*, p.b_count
FROM
banners_dynamic b
INNER JOIN (
SELECT
b_id,
COUNT(*) AS b_count
FROM
banner_views v
WHERE
v.b_date >= DATE(NOW() - INTERVAL 7 DAY)
GROUP BY
b_id
) p on p.b_id = b.id
WHERE
b.static_keywords LIKE '%test%'
AND b.`status` = '1'
AND b.static_type = '1'
ORDER BY
p.b_count ASC
LIMIT 3
UPDATE: You can do it even without subquery:
SELECT
b.*, COUNT(v.b_id) AS b_count
FROM
banners_dynamic b
INNER JOIN banner_views v ON v.b_id = b.id
WHERE
v.b_date >= DATE_ADD(NOW(), INTERVAL - 7 DAY)
AND b.static_keywords LIKE '%test%'
AND b.`status` = '1'
AND b.static_type = '1'
GROUP BY
v.b_id
ORDER BY
b_count ASC
LIMIT 3;
If you want to include banners without any views (count=0) then you must do a LEFT JOIN:
SELECT
b.*, COUNT(v.b_id) AS b_count
FROM
banners_dynamic b
LEFT JOIN banner_views v ON v.b_id = b.id
AND v.b_date >= DATE_ADD(NOW(), INTERVAL - 7 DAY)
WHERE
b.static_keywords LIKE '%test%'
AND b.`status` = '1'
AND b.static_type = '1'
GROUP BY
v.b_id
ORDER BY
b_count ASC
LIMIT 3;

Combine and use arithmetic on SQL values from two different tables

I have a table with data of guests to an event. I can retrieve the number of people who have attended (membersAttended) with this query:
SELECT COUNT(DISTINCT g.`name1`) AS `membersAttended`
FROM `tmc_doorapp_guests` g
LEFT JOIN `tmc_doorapp_events` e
ON e.`id` = g.`event_id`
WHERE `name1` REGEXP '^[0-9]+$'
AND e.`date` > DATE_SUB(NOW(), INTERVAL 30 DAY)
AND g.`checkin` = 1;
To retrieve the total number of members (totalMembers) I use:
SELECT COUNT(DISTINCT `id`) AS `totalMembers`
FROM `tmc_users`;
To get a percentage value (totalPercent) of members who have attended across the total members, I use PHP to make the two queries and then calculate like so:
$totalPercent = number_format(($membersAttended/$totalMembers*100),2);
I've tried combining the two queries and the percentage calculation in a similar way to below, with no luck:
SELECT COUNT(DISTINCT g.`name1`) AS `membersAttended`,
COUNT(DISTINCT m.`id`) AS `totalMembers`,
(`membersAttended` * 100 / `totalMembers`) AS `totalPercent`
FROM `tmc_doorapp_guests` g, `tmc_users` m
LEFT JOIN `tmc_doorapp_events` e
ON e.`id` = g.`event_id`
WHERE `name1` REGEXP '^[0-9]+$'
AND e.`date` > DATE_SUB(NOW(), INTERVAL 30 DAY)
AND g.`checkin` = 1;
I also tried expanding out the columns:
SELECT COUNT(DISTINCT g.`name1`) AS `membersAttended`,
COUNT(DISTINCT m.`id`) AS `totalMembers`,
(COUNT(DISTINCT g.`name1`) * 100 / COUNT(DISTINCT m.`id`)) AS `totalPercent`
FROM `tmc_doorapp_guests` g, `tmc_users` m
LEFT JOIN `tmc_doorapp_events` e
ON e.`id` = g.`event_id`
WHERE `name1` REGEXP '^[0-9]+$'
AND e.`date` > DATE_SUB(NOW(), INTERVAL 30 DAY)
AND g.`checkin` = 1;
This gives me the error:
Error code: 1054. Unknown column 'g.event_id' in 'on clause'
How can I combine these SQL/PHP queries/calculations into one SQL query?
You could use subquery:
SELECT COUNT(DISTINCT g.`name1`) AS `membersAttended`,
(SELECT COUNT(DISTINCT `id`) FROM `tmc_users`) AS `totalMembers`,
COUNT(DISTINCT g.`name1`) * 100 / (SELECT COUNT(DISTINCT `id`)
FROM `tmc_users`) AS `totalPercent`
FROM `tmc_doorapp_guests` g
LEFT JOIN `tmc_doorapp_events` e
ON e.`id` = g.`event_id`
WHERE `name1` REGEXP '^[0-9]+$'
AND e.`date` > DATE_SUB(NOW(), INTERVAL 30 DAY)
AND g.`checkin` = 1;

Mysql Query- for each date max 3 datas

these is my DB table data,{ i have maintained only one Table}
I need to fetch max 3 data from each start_date,
give me any idea to develop query,,
SELECT a.*
FROM Table1 a
INNER JOIN Table1 b ON a.start_date = b.start_date AND a.event_id <= b.event_id
GROUP BY a.event_id,a.start_date
HAVING COUNT(*) <= 3
ORDER BY a.start_date
I may suggest you this query -
SELECT * FROM (
SELECT t1.*, COUNT(*) pos FROM table t1
LEFT JOIN table t2
ON t2.start_date = t1.start_date AND t2.event_id <= t1.event_id
GROUP BY
t1.start_date AND t1.event_id
) t
WHERE
pos <= 3;
It selects 3 rows with min event_id in a start_date group.

INSERT .. SELECT multiple rows from multiple tables

I need to record the number of items requested and issued against each item every day. The purchase_doc table is:
The requested_items table contains item requested as follows:
The movement table contains item requested as follows:
The need output (data to be inserted) is:
One way of doing this is to fetch items issued and requested from the first 2 queries, and then build an array of items issued and requested against each item id, and then insert these values in the daily_movement table, like this:
SELECT n.item_id AS n__item_id, SUM(n.qty) AS qty
FROM requested_items n LEFT JOIN purchase_doc doc ON n.doc_id = doc.id
WHERE (doc.type = 'Item Request' AND doc.created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR))
GROUP BY n.item_id
SELECT n.item_id AS item_id, SUM(n.qty) AS qty
FROM movement n LEFT JOIN purchase_doc doc ON n.doc_id = doc.id
WHERE (doc.type = 'Store Issue' AND doc.created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR))
GROUP BY n.item_id
From these and other SELECTs, I need to insert a single row per item per day containing the qty of requests, issues, etc for this item in this fashion:
INSERT INTO daily_movement date, item_id, requested_qty, issued_qty VALUES ( NOW(), 23, 4, 5), ( NOW(), 25, 5, 5), ( NOW(), 113, 6, 8);
But there will be too many SELECTs (since I also need other activities performed per item), followed by an insert.
My question is: Is it possible to do this via a single SELECT ... INSERT statement. If not, can somebody suggest a more elegant way of doing this
I'm thinking this, but it might be over-simplified:
INSERT INTO `daily_movement`
(`date`, `item_id`, `requested_qty`, `issued_qty`)
SELECT NOW(), `r`.`item_id`, SUM(`r`.`qty`), SUM(`m`.`qty`)
FROM `purchase_doc` `d`
JOIN `requested_items` `r`
ON `r`.`doc_id` = `d`.`id`
LEFT JOIN `movement` `m`
ON `m`.`doc_id` = `d`.`id`
WHERE
(`d`.`type` = 'Item Request' OR `d`.`type` = 'Store Issue')
AND
`d`.`created_at` > DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY `r`.`item_id`
EDIT
This is my final answer, with a nasty UNION to get around MySQL's lack of FULL OUTER JOIN:
INSERT INTO `daily_movement`
(`date`, `item_id`, `week_no`, `requested_qty`, `issued_qty`)
SELECT *
FROM (
(
SELECT COALESCE(`r`.`item_id`, `a`.`item_id`) AS `item_id`, CURDATE() AS `date`, NULL AS `week_no`, SUM(`r`.`qty`) AS `requests`, COALESCE(`a`.`issued`, 0) AS `issued`
FROM `purchase_doc` `d`
LEFT JOIN `requested_items` `r`
ON `r`.`doc_id` = `d`.`id`
LEFT JOIN (
SELECT `m`.`item_id`, SUM(`m`.`qty`) AS `issued`
FROM `purchase_doc` `d`
JOIN `movement` `m`
ON `m`.`doc_id` = `d`.`id`
WHERE `d`.`type` = 'Store Issue'
AND `d`.`created_at` > DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY `m`.`item_id`
) `a`
ON `a`.`item_id` = `r`.`item_id`
WHERE `d`.`type` = 'Material Requisition'
AND `d`.`created_at` > DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY `r`.`item_id`
) UNION DISTINCT (
SELECT COALESCE(`m`.`item_id`, `a`.`item_id`) AS `item_id`, CURDATE() AS `date`, NULL AS `week_no`, COALESCE(`a`.`requests`, 0) AS `requests`, SUM(`m`.`qty`) AS `issued`
FROM `purchase_doc` `d`
LEFT JOIN `movement` `m`
ON `m`.`doc_id` = `d`.`id`
LEFT JOIN (
SELECT `r`.`item_id`, SUM(`r`.`qty`) AS `requests`
FROM `purchase_doc` `d`
JOIN `requested_items` `r`
ON `r`.`doc_id` = `d`.`id`
WHERE `d`.`type` = 'Material Requisition'
AND `d`.`created_at` > DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY `r`.`item_id`
) `a`
ON `a`.`item_id` = `m`.`item_id`
WHERE `d`.`type` = 'Store Issue'
AND `d`.`created_at` > DATE_SUB(NOW(), INTERVAL 24 HOUR)
GROUP BY `m`.`item_id`
)
ORDER BY `item_id`
) `u`
http://sqlfiddle.com/#!2/3923d/13
you can use the union operator here or here to get all your results in a single select
You can use a query like this -
edited:
INSERT INTO daily_movement(date, item_id, requested_qty, issued_qty)
SELECT i.item_id, SUM(ri.qty) requested_qty, SUM(m.qty) issued_qty FROM
(SELECT item_id FROM requested_items UNION SELECT item_id FROM movement) i
LEFT JOIN (
SELECT n.item_id, n.qty
FROM requested_items n LEFT JOIN purchase_doc doc ON n.doc_id = doc.id
WHERE doc.type = 'Item Request' AND doc.created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)
) ri
ON ri.item_id = i.item_id
LEFT JOIN (
SELECT n.item_id, n.qty
FROM movement n LEFT JOIN purchase_doc doc ON n.doc_id = doc.id
WHERE doc.type = 'Store Issue' AND doc.created_at > DATE_SUB(NOW(), INTERVAL 24 HOUR)
) m
ON m.item_id = i.item_id
GROUP BY
i.item_id;

Categories