How to use subquery with group by in mysql? - php

I have one table with multiple rows for particular users.i am having
data with many years like 2019,2018,2016 and more. i have two
scenarios:
1.i want data of particular INVOICE_YEAR.
2,but same time i want FIRST DATE OF INVOICE GENERATED FOR PARTICULAR
USER.
my sql query :
$yearOf this is dynamic year input variable.
$yearOf = 2019;
$Records = "SELECT MIN(inv.INVOICE_DATE) AS MIN_INVOICE_DATE
FROM invoices as inv
LEFT JOIN customers as cm ON cm.CUSTOMER_ID = inv.CUSTOMER_ID
where inv.INVOICE_YEAR IN (".$yearOf.")
group by inv.CUSTOMER_ID ORDER BY cm.CUSTOMER_NAME ASC";
As you can see my query if i want data of all users where INVOICE_YEAR IN ('2019').My first condition will satisfied i will get all data of users where INVOICE_YEAR = 2019.
But same time i want first invoice date so for this i used MIN(inv.INVOICE_DATE) but as i used
where inv.INVOICE_YEAR IN (".$yearOf.") this in where condition so it gives me first invoice date of particular year.
But i want first invoice date from whole table for all users.
I tried with subquery but it shows me error of Subquery returns more than 1 row
My query with subquery:
$Records = "SELECT
(
SELECT MIN(inv.INVOICE_DATE) AS MIN_INVOICE_DATE FROM invoices AS inv GROUP BY inv.CUSTOMER_ID) AS MIN_INVOICE_DATE
FROM invoices as inv
LEFT JOIN customers as cm ON cm.CUSTOMER_ID = inv.CUSTOMER_ID
where inv.INVOICE_YEAR IN (".$yearOf.")
group by inv.CUSTOMER_ID ORDER BY cm.CUSTOMER_NAME ASC";
For eg:
3 customers are there 101,102,103
data in table is like:
id | customer_id | invoice_date | invoice_year
1 | 101 | 2019-01-01 | 2019
2 | 101 | 2016-01-01 | 2016
3 | 101 | 2017-01-01 | 2017
4 | 101 | 2016-01-02 | 2016
5 | 102 | 2019-01-02 | 2019
6 | 103 | 2018-01-02 | 2018
7 | 103 | 2019-01-07 | 2019
8 | 102 | 2015-01-02 | 2015
As i Request query to get data of INVOICE_YEAR 2019 with first invoice date of particular user so it should give output like :
id | customer_id | invoice_date | invoice_year | min_invoice_date
1 | 101 | 2019-01-01 | 2019 | 2016-01-01
5 | 102 | 2019-01-02 | 2019 | 2015-01-02
7 | 103 | 2019-01-07 | 2019 | 2019-01-07
With as i want first invoice date IN COLUMN MIN_INVOICE_DATE of all users.
But it shows me data like :
id | customer_id | invoice_date | invoice_year | min_invoice_date
1 | 101 | 2019-01-01 | 2019 | 2019-01-01
5 | 102 | 2019-01-02 | 2019 | 2019-01-02
7 | 103 | 2019-01-07 | 2019 | 2019-01-07

You want to pull out the earliest invoice for each customer in 2019, along with the date of their earliest invoice within the whole table.
In MySQL 8.0, you can solve this using window functions:
SELECT id, customer_id, invoice_date, invoice_year, min_invoice_date
FROM (
SELECT
t.*,
ROW_NUMBER() OVER(PARTITION BY customer_id, invoice_year ORDER BY invoice_date) rn,
MIN(invoice_date) OVER(PARTITION BY customer_id) min_invoice_date
FROM mytable t
) x
WHERE invoice_year = 2019 AND rn = 1
In earlier versions, you can:
JOIN the table with a query that computes the overall minimum invoice_date per customer
use a correlated subquery with a NOT EXISTS condition to filter on the earliest invoice par customer in 2019
Query:
SELECT t.id, t.customer_id, t.invoice_date, t.invoice_year, m.min_invoice_date
FROM mytable t
INNER JOIN (
SELECT customer_id, MIN(invoice_date) min_invoice_date
FROM mytable
GROUP BY customer_id
) m ON m.customer_id = t.customer_id
WHERE
t.invoice_year = 2019
AND NOT EXISTS (
SELECT 1
FROM mytable t1
WHERE t1.invoice_year = 2019
AND t1.customer_id = t.customer_id
AND t1.invoice_date < t.invoice_date
)
In this demo on DB Fiddle, both queries return:
| id | customer_id | invoice_date | invoice_year | min_invoice_date |
| --- | ----------- | ------------ | ------------ | ---------------- |
| 1 | 101 | 2019-01-01 | 2019 | 2016-01-01 |
| 5 | 102 | 2019-01-02 | 2019 | 2015-01-02 |
| 7 | 103 | 2019-01-07 | 2019 | 2018-01-02 |

I guess you want the to see the details of the first (earliest-dated) invoice for each customer in each calendar year. You want that result filtered to cover only one year.
So, start with a subquery to find the date of the first invoice for every customer in each calendar year. (https://www.db-fiddle.com/f/bmBZ14Vr9Re6ahpfs2FF2X/0)
SELECT MIN(invoice_date) first_invoice_date,
YEAR(invoice_date) calendar_year,
customer_id
FROM invoices
GROUP BY YEAR(invoice_date), customer_id
Then retrieve the detail for those invoices by JOINing that subquery to your original invoices table. (https://www.db-fiddle.com/f/bmBZ14Vr9Re6ahpfs2FF2X/1)
SELECT invoices.*
FROM invoices
JOIN (
SELECT MIN(invoice_date) first_invoice_date,
YEAR(invoice_date) calendar_year,
customer_id
FROM invoices
GROUP BY YEAR(invoice_date), customer_id
) firsts
ON invoices.customer_id = firsts.customer_id
AND invoices.invoice_date = firsts.first_invoice_date
ORDER BY invoices.customer_id,
invoices.invoice_year,
invoices.invoice_date
Then, throw in WHERE invoices.invoice_year = 2019 to get just the year you want.
Notice that your invoice_year column is unnecessary, since it can always be computed from YEAR(invoice_date). You should consider getting rid of it.

Related

Eloquent SELECT from UNION result

I have two different tables with the (almost) the same structure:
(not the best DB design, but unfortunately out of my control)
Table A:
+-----------+------+-------+-----+
| client_id | year | month | fee |
+-----------+------+-------+-----+
| 33 | 11 | 2022 | 11 |
| 42 | 11 | 2022 | 13 |
| 33 | 12 | 2022 | 27 |
| 16 | 12 | 2022 | 15 |
+-----------+------+-------+-----+
Table B:
+-----------+------+-------+-----+
| client_id | year | month | fee |
+-----------+------+-------+-----+
| 33 | 11 | 2022 | 19 |
| 57 | 11 | 2022 | 34 |
+-----------+------+-------+-----+
I want to SUM fees of all clients grouping bu month and year.
For one table the eloquent query is simple:
$queryA = DB::table('A')
->selectRaw('month, year, COUNT(*) AS total, SUM(fee) AS total_fee')
->groupBy(['month', 'year']);
($queryB will be the same, with ->table('B') instead ).
In order to get total sum of both tables, I want to use UNION.
The approach:
I want to apply a SELECT query on the result returned by UNION:
SELECT month, year, COUNT(*) AS total, SUM(total_fee) AS total_fee
FROM
(
(
SELECT month, year, COUNT(*) AS total, SUM(fee) AS total_fee
FROM A
GROUP BY month, year
) UNION (
SELECT month, year, COUNT(*) AS total, SUM(fee) AS total_fee
FROM B
GROUP BY month, year
)
) AS result_table
GROUP BY month, year
ORDER BY year DESC, month DESC;
The problem:
I tried this:
$queryA
->union($queryB)
->select(month, year, COUNT(*) AS total, SUM(total_fee) AS total_fee)
->groupBy(['month', 'year'])
the new SELECT statement is inserted into the $queryA sub-query.
Any idea how to achieve what I am looking for?

MySQL and PHP: Getting a SUM from a row in column A based on a DATE from column A joined by an ID in column B?

So, as the title says, I think I want to get the SUM of a row in column A (Meta Value) based on matching DATEs in column A (Meta Value) joined from IDs in column B (Item ID).
Essentially, I want to look for a specific date 2017-05-05 in Meta Value. Then, when a date is a match, find the Item ID. In the example below, this would be 2 and 3. Then, get the SUM of the Field ID (11) for both Item ID 2 and Item ID 3 and return the SUM to a variable in PHP.
Here is what my data looks like:
+-----------+------------+------------+
| Meta Value| Field ID | Item ID |
+-----------+------------+------------+
| John | 8 | 1 |
|john#e.com | 10 | 1 |
| 2 | 11 | 1 |
|2016-11-20 | 12 | 1 |
| Mary | 8 | 2 |
|mary#e.com | 10 | 2 |
| **5** | 11 | 2 |
|2017-05-05 | 12 | 2 |
| Mike | 8 | 3 |
|mike#e.com | 10 | 3 |
| **2** | 11 | 3 |
|2017-05-05 | 12 | 3 |
+-----------+------------+------------+
I am after the SUM of 7 from Mike and Mary.
My current wordpress php call looks like this (but only gets me row count):
$bookings = $wpdb->get_var("SELECT COUNT(*) FROM wp_frm_item_metas WHERE field_id=12 AND meta_value='$select_date'");
Any help is appreciated!
seems you need sum on a self join
select sum(a.field_id)
from wp_frm_item_metas a
inner join wp_frm_item_metas b on b.item_id = a.item_id
and b.meta_value = '$select_date'
but if you need the sum for meta_value (11) you should
select sum(a.meta_vale)
from wp_frm_item_metas a
inner join wp_frm_item_metas b on b.item_id = a.item_id
and b.meta_value = '$select_date'
and a.filed_id =11

Fetch Products Count for specific week in mysql

I have 3 tables
Orders
id | name | order_date | total
------------------------------
1 | ABCD | 2017-03-29 | 60
2 | KJHS | 2017-03-29 | 80
3 | HGGG | 2017-03-30 | 90
item_orders
id | order_id | item_id
-----------------------
1 | 1 | 1
2 | 1 | 2
3 | 2 | 1
4 | 2 | 2
items
id | item_name | desc | price |
---------------------------------
1 | Brown | jdsa | 20
Cardigan XL
---------------------------------
2 | Red Socks | sada | 30
---------------------------------
My Query which I have wrote is
SELECT orders.*, item_orders.item_id,items.item_name,items.description,items.price
FROM ((orders
INNER JOIN item_orders ON orders.id = item_orders.item_id)
INNER JOIN items ON item_orders.item_id = items.id)
WHERE WEEKOFYEAR(orders.order_date)=WEEKOFYEAR(NOW());
Now I wanted to bring item_count total from orders table of current week with its total.
Something like these shows current week stats
BrownCardigan XL 12 $200
Red Socks 15 $350
Something like these.
I am bringing data from orders table by above query and Now I am stuck of how to count the items from order table and sum of prices for the current week.
you could use aggreagation function and group by
SELECT items.item_name, sum(orders.total), sum(orders.total*items.price)
FROM orders
INNER JOIN item_orders ON orders.id = item_orders.item_id
INNER JOIN items ON item_orders.item_id = items.id
WHERE WEEKOFYEAR(orders.order_date)=WEEKOFYEAR(NOW()
GROUP BY items.item_name
;

get first and last value of a groupby object in laravel 5 and mysql

I have a table called income.
+----+-------------+---------------------+--------+--------+--------+-----------+---------------------+---------------------+
| id | employee_id | date | gross | income | credit | comission | created_at | updated_at |
+----+-------------+---------------------+--------+--------+--------+-----------+---------------------+---------------------+
| 1 | 1 | 2016-03-30 19:21:09 | 100.00 | 29.00 | 11.00 | 60.00 | 2016-03-31 19:21:46 | 2016-03-31 19:21:46 |
| 2 | 1 | 2016-03-31 19:24:44 | 110.00 | 43.00 | 1.00 | 60.00 | 2016-03-31 19:24:56 | 2016-03-31 19:24:56 |
| 3 | 2 | 2016-03-31 21:44:09 | 77.00 | 30.80 | 0.00 | 60.00 | 2016-03-31 21:44:19 | 2016-03-31 21:44:19 |
+----+-------------+---------------------+--------+--------+--------+-----------+---------------------+---------------------+
what i want to do is query these and group it by employee_id and i want the date it started and date it end. What i got is
$records = Income::whereBetween('date', [$start, $end])
->groupBy('employee_id')
->selectRaw('store_incomes.* , sum(gross) as total_gross , sum(income) as total_income, sum(credit) as total_credit')
->get();
This always return the first date for that employee. For example, employee_id 1 always return the date of 2016-03-30 19:21:09. What i want is to get the first and last date for each employee_id, so employee id 1 would have start date of 2016-30-30 and end date of 2016-03-31. Is there a way to do this without messy manual code?
For the current code my output is :
[
{"id":"1","employee_id":"1","date":"2016-03-30 19:21:09","gross":"100.00","income":"29.00","credit":"11.00","comission":"60.00","created_at":"2016-03-31 19:21:46","updated_at":"2016-03-31 19:21:46","total_gross":"210.00","total_income":"72.00","total_credit":"12.00"},
{"id":"3","employee_id":"2","date":"2016-03-31 21:44:09","gross":"77.00","income":"30.80","credit":"0.00","comission":"60.00","created_at":"2016-03-31 21:44:19","updated_at":"2016-03-31 21:44:19","total_gross":"77.00","total_income":"30.80","total_credit":"0.00"}
]
My expected output is to include 2 more values (start_date and end_date):
[
{"id":"1","employee_id":"1","start_date":"2016-03-30 19:21:09", "end_date":"2016-03-31 19:24:44"},
{"id":"3","employee_id":"2","start_date":"2016-03-31 21:44:09", "end_date":"2016-03-31 21:44:09"}
]
The raw MySQL query you want is something along these lines:
SELECT MIN(date) AS start_date, MAX(date) AS end_date, store_incomes.*,
SUM(gross) AS total_gross , SUM(income) AS total_income, SUM(credit) AS total_credit
FROM income
GROUP BY employee_id
To do this in Laravel, just add MIN() and MAX() to your raw query:
$records = DB::Income
->selectRaw('store_incomes.* , min(date) as start_date, max(date) as end_date, sum(gross) as total_gross , sum(income) as total_income, sum(credit) as total_credit')
->groupBy('employee_id')
->get();

mysql select all unique rows in one column and all max rows in another column by datetime

What I need is to get the most recent (by date_time) unique player_id for each table_id
Table:
buyin_id player_id table_id date_time
---------|-----------|----------|--------------------|
1 | 10 | 21 | 2015-01-26 00:00:01
2 | 11 | 21 | 2015-01-26 00:00:02
3 | 12 | 21 | 2015-01-26 00:00:03
4 | 10 | 21 | 2015-01-26 00:00:04
5 | 11 | 21 | 2015-01-26 00:00:05
6 | 12 | 22 | 2015-01-26 00:00:06
7 | 13 | 22 | 2015-01-26 00:00:07
8 | 13 | 22 | 2015-01-26 00:00:08
Desired result:
buyin_id player_id table_id date_time
---------|-----------|----------|--------------------|
3 | 12 | 21 | 2015-01-26 00:00:03
4 | 10 | 21 | 2015-01-26 00:00:04
5 | 11 | 21 | 2015-01-26 00:00:05
6 | 12 | 22 | 2015-01-26 00:00:06
8 | 13 | 22 | 2015-01-26 00:00:08
I tried something like this which returns only 1 row instead of 1 row per table_id
SELECT pb.buyin_id, pb.player_id, pb.buyin, pb.cashout, pb.cashout_error, pb.date_time
FROM poker_buyin AS pb
INNER JOIN (SELECT player_id, MAX(date_time) AS MaxDateTime
FROM poker_buyin GROUP BY player_id) groupedpb
ON pb.player_id = groupedpb.player_id
AND pb.date_time = groupedpb.MaxDateTime
WHERE pb.player_id = '$player_id'";
The query you've mentioned finds the most recent record for each player id. And then you filter it to find just one player, so you get one row.
If you want to find the most recent record for each player and table, your inner query needs to be this:
SELECT MAX(buyin_id) buyin_id
FROM poker_buyin
GROUP BY player_id, table_id
This will get the row ids from your table that represent the latest player / table combinations.
Then you use that to pull records from your table, like this (http://sqlfiddle.com/#!2/be68b7/2/0)
SELECT whatever_columns
FROM poker_buyin
WHERE buyin_id IN
(
SELECT MAX(buyin_id) buyin_id
FROM poker_buyin
GROUP BY player_id, table_id
)
WHERE player_id = '$player_id'
ORDER BY player_id, table_id
There's a little trick in this query: The buyin_id value continually goes up, so it's a nice way of selecting the latest-in-time records for each combination.
if you don't need buyin_id in result columns that is simple:
SELECT DISTINCT player_id, table_id, max(date_time) as dt
FROM `poker_buyin `
GROUP BY player_id, table_id

Categories