SQL join with other table and adding a case - php

This following query is telling me how many sales was at the same day.
also how many new users, and credits.
This is my working query (it works great!):
SELECT Substring(purchase.`date`,1,10) AS `DayDate`,
Sum(Cast(Substring(purchase.`item`, 12) AS UNSIGNED)) AS `Credit`,
Count(1) AS `Sales`,
(SELECT Count(*) FROM enswitch_mobile_users WHERE Date(purchase.`date`) = Substring(enswitch_mobile_users.`creation_date`,1,10)) AS `New_users`
FROM (SELECT item, date
FROM enswitch_new_iphone_purchases WHERE `status`=1
UNION
SELECT item, date
FROM enswitch_new_android_purchases WHERE `status`=1) AS `purchase`
WHERE purchase.`date` >= :from_date AND purchase.`date` <= :to_date
GROUP BY `DayDate`
ORDER BY `DayDate` DESC
I am searching here in 3 tables.
enswitch_new_android_purchases enswitch_new_iphone_purchase
they both has item, user_id, status and date columns.
example for one entry:
date: 2012-08-01 16:24:30
item: xsalnx.sip.70
user_id: 1337
status: 1
Also pulling the mobile_users amount from enswitch_mobile_users(id, creation_date, mobile id, ...) and grouping with specific day date.
What I am trying to do is to add a test if the user who bought, or the new user is a tester. if so I want to ignore this data on my query.
I'm saving the testers on a table called:
enswitch_testing_devices (id, name, mobile_id).
And I can join the data with enswitch_mobile_users (mobile_id column).
So far I tried to make it work but had no luck..
How can I do this query ?

Try below - just added a clause when you get the users - get all the users except test. Now a sample data and structure table would help. (I think you can re-write the query.)
SELECT Substring(purchase.`date`,1,10) AS `DayDate`,
Sum(Cast(Substring(purchase.`item`, 12) AS UNSIGNED)) AS `Credit`,
Count(1) AS `Sales`,
(
SELECT Count(*)
FROM enswitch_mobile_users
WHERE
Date(purchase.`date`) = Substring(enswitch_mobile_users.`creation_date`,1,10)
AND enswitch_mobile_users.mobile_id NOT IN ( select mobile_id from enswitch_testing_devices WHERE 'is tester')
) AS `New_users`
FROM (SELECT item, date
FROM enswitch_new_iphone_purchases WHERE `status`=1
UNION
SELECT item, date
FROM enswitch_new_android_purchases WHERE `status`=1) AS `purchase`
WHERE purchase.`date` >= :from_date AND purchase.`date` <= :to_date
GROUP BY `DayDate`
ORDER BY `DayDate` DESC

I manage to SOLVE this issue.
If any one wondered.
function search_daily_sales($from_date, $to_date ,$show_testers)
{
// If not showing the testers
if ($show_testers === false)
{
$sql = "SELECT Substring(purchase.`date`,1,10) AS `DayDate`,
Sum(CASE WHEN td.mobile_id IS NULL
THEN Cast(Substring(purchase.`item`, 12) AS UNSIGNED)
ELSE '0' END) AS `Credit`,
Sum(CASE WHEN td.mobile_id IS NULL THEN '1' ELSE '0' END) AS `Sales`,
(SELECT Count(*) FROM enswitch_mobile_users
WHERE
Date(purchase.`date`) = Substring(enswitch_mobile_users.`creation_date`,1,10)
AND enswitch_mobile_users.`mobile_id` NOT IN (SELECT mobile_id FROM enswitch_testing_devices)) AS `New_users`,
MIN(CASE WHEN td.mobile_id IS NULL THEN '0' ELSE '1' END) AS `tester`
FROM (SELECT item, date, user_id
FROM enswitch_new_iphone_purchases WHERE `status`=1
UNION
SELECT item, date, user_id
FROM enswitch_new_android_purchases WHERE `status`=1) AS `purchase`
LEFT JOIN enswitch_mobile_users mu ON mu.id = purchase.user_id
LEFT JOIN enswitch_testing_devices td ON td.mobile_id = mu.mobile_id
WHERE purchase.`date` >= :from_date AND purchase.`date` <= :to_date
GROUP BY `DayDate`
ORDER BY `DayDate` DESC";
}
else
{
$sql = "SELECT Substring(purchase.`date`,1,10) AS `DayDate`,
Sum(Cast(Substring(purchase.`item`, 12) AS UNSIGNED)) AS `Credit`,
Count(1) AS `Sales`,
(SELECT Count(*) FROM enswitch_mobile_users WHERE Date(purchase.`date`) = Substring(enswitch_mobile_users.`creation_date`,1,10)) AS `New_users`
FROM (SELECT item, date
FROM enswitch_new_iphone_purchases WHERE `status`=1
UNION
SELECT item, date
FROM enswitch_new_android_purchases WHERE `status`=1) AS `purchase`
WHERE purchase.`date` >= :from_date AND purchase.`date` <= :to_date
GROUP BY `DayDate`
ORDER BY `DayDate` DESC";
}
$result = DB::query(Database::SELECT, $sql)->bind(':from_date', $from_date)->
bind(':to_date', $to_date)->execute();
return $result;
}

Related

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;

How to add multiple limits in mysql query?

I want to select SUM of last 200,100 and 50 rows of close price from a table in a single query.
given below is the query for 200 rows.
SELECT SUM(Close_price) as tot200 FROM cash_data ORDER BY date_added LIMIT 0,200
can anyone help me with this.
You can use sub queries -
SELECT
(SELECT SUM(Close_price) FROM cash_data ORDER BY date_added LIMIT 0,200) as tot200,
(SELECT SUM(Close_price) FROM cash_data ORDER BY date_added LIMIT 0,100) as tot100,
(SELECT SUM(Close_price) FROM cash_data ORDER BY date_added LIMIT 0,50) as tot50
To make it in a single select without any subselects you can use a ranking varaible and sum conditionally
SELECT #rank := #rank + 1,
SUM(case when #rank <= 50 then Close_price else 0 end) as top_50_sum,
SUM(case when #rank <= 100 then Close_price else 0 end) as top_100_sum,
SUM(case when #rank <= 200 then Close_price else 0 end) as top_200_sum
FROM cash_data
cross join (select #rank := 0) r
ORDER BY date_added
LIMIT 0,200
Thanks for all the replies. Actually both the answers are working but i choose the second one and made some changes for my need. Below is the final query
SELECT
(SELECT SUM(Close_price)/200 FROM (SELECT Close_price FROM cash_data WHERE SERIES='$series' AND SYMBOL='$symbol' AND date_added <= '$date' ORDER BY date_added DESC LIMIT 0,200) as tot200) as avg200,
(SELECT SUM(Close_price)/100 FROM (SELECT Close_price FROM cash_data WHERE SERIES='$series' AND SYMBOL='$symbol' AND date_added <= '$date' ORDER BY date_added DESC LIMIT 0,100) as tot100) as avg100,
(SELECT SUM(Close_price)/50 FROM (SELECT Close_price FROM cash_data WHERE SERIES='$series' AND SYMBOL='$symbol' AND date_added <= '$date' ORDER BY date_added DESC LIMIT 0,50) as tot50) as avg50
Thank you all.

how to show date but data in my database type is datetime?

i want the output to show the date. but in the same time i want to filter by time.
SELECT CAST(t.req_date as Date) as Date,
SUM(t.Transaction)+SUM(r.Request) as allTransaction,
SUM(t.Success)+SUM(r.RequestSuccess) as allSuccess, t.Transaction,
t.Success, r.Request, r.RequestSuccess
FROM (select req_date, count(*) as transaction, sum(t.status = 0) as success
from transfer_tx_201503 as t WHERE CAST(t.req_date as Time) >='00:00:00' AND
CAST(t.req_date as Time) <= '23:00:00'
group by req_date desc) as t JOIN
(select req_date, count(*) as Request, SUM(r.status = 0) as RequestSuccess
from request_tx_201503 as r WHERE CAST(r.req_date as Time) >='00:00:00' AND
CAST(r.req_date as Time) <= '23:00:00'
group by req_date desc) as r
ON CAST(t.req_date as Date) = CAST(r.req_date as Date)
GROUP BY CAST(`date` as Date) desc
The most simple way would be to use date function on datetime column.
mysql> select date(now());
+-------------+
| date(now()) |
+-------------+
| 2015-03-30 |
+-------------+
1 row in set (0.00 sec)
i have find my own solution. i use cast() to convert the data type.
SELECT CAST(t.req_date as Date) as Date, SUM(t.Transaction)+SUM(r.Request) as
allTransaction, SUM(t.Success)+SUM(r.RequestSuccess) as allSuccess,
t.Transaction, t.Success, r.Request, r.RequestSuccess
FROM
(select req_date, count(DISTINCT no_a) as Transaction, sum(t.status = 0) as Success
from transfer_tx_201503 as t WHERE CAST(t.req_date as time) BETWEEN '00:00:00' AND '$searchterm'
group by CAST(req_date as Date) desc) as t
JOIN
(select req_date, count(DISTINCT no_a) as Request, SUM(r.status = 0) as RequestSuccess
from request_tx_201503 as r WHERE CAST(r.req_date as time) BETWEEN '00:00:00' AND '$searchterm'
group by CAST(req_date as Date) desc) as r
ON CAST(t.req_date as date) = CAST(r.req_date as date)
GROUP BY Date desc

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;

MYSQL query not the result I looking for

I have this query:
SELECT gamer_id,COUNT(*) AS sum, SUM(amount) as amount
FROM sales_list
WHERE rdate BETWEEN '2012-04-01' AND '2012-04-30' AND gamer_id NOT IN
(SELECT gamer_id FROM sales_list WHERE rdate < '2012-04-01' GROUP BY gamer_id)
GROUP BY gamer_id
This query printed me "2" results and I'm looking just "1".
I have 1 gamer's that deposit 2 times in April and I don't want to count the total deposits just to count the total gamer's that deposited.
any advice?
I don't really get it, but you want the numbers of deposits of a gamer only or the amount he deposited in addition?!
This should deliver number of deposits:
SELECT gamer_id, COUNT(gamer_id) AS sum, SUM(amount) as amount
FROM sales_list
WHERE rdate BETWEEN '2012-04-01' AND '2012-04-30'
GROUP BY gamer_id
HAVING COUNT(gamer_id)>0
Edit:
SELECT DISTINCT gamer_id
FROM sales_list
WHERE rdate BETWEEN '2012-04-01' AND '2012-04-30'
AND gamer_id NOT IN (SELECT gamer_id
FROM sales_list
WHERE rdate < '2012-04-01')
GROUP BY gamer_id
try this:
SELECT sl.gamer_id,COUNT(*) AS sum, SUM(sl.amount) as amount
FROM sales_list sl
WHERE sl.rdate BETWEEN '2012-04-01' AND '2012-04-30' AND sl.gamer_id NOT IN
(SELECT sl1.gamer_id FROM sales_list sl1 WHERE sl1.rdate < '2012-04-01' GROUP BY sl1.gamer_id)
GROUP BY sl.gamer_id

Categories