I have a table prices with where I store more times in a day more values referred to a customer like this:
Table prices:
| id | customer_id | value_1 | value_2 | value_3 | created_at |
-------------------------------------------------------------------------
| 1 | 10 | 12345 | 122 | 10 | 2021-08-11 10:12:40 |
| 2 | 10 | 22222 | 222 | 22 | 2021-08-11 23:56:20 |
| 3 | 12 | 44444 | 444 | 44 | 2021-08-12 08:12:10 |
| 4 | 10 | 55555 | 555 | 55 | 2021-08-13 14:11:20 |
| 5 | 10 | 66666 | 666 | 66 | 2021-08-13 15:15:30 |
| 6 | 10 | 77777 | 777 | 77 | 2021-08-13 16:12:50 |
I have some filters on that table to retrieve only records with date greater than X and/or lower than Y, sort records by value_1 or value_2, etc...
With that filters I have to take only 1 record for each day of a customer specified.
I'm able to get the record with the highest value_1 for example, by using sql function max() and group by date.
// Init query
$query = Price::query();
// Take the greatest value of value1
$query = $query->selectRaw(
'max(value_1) as highest_value_1, ' .
'date(created_at) as date'
);
// If defined, add a greater or equals
if ($from) $query->where("created_at", ">=", $from);
// If defined add a lower or equals
if ($to) $query->where("created_at", "<=", $to);
// Get results for current customer only, grupping by date and ordering it
$query = $query->where('customer_id', $id)->groupBy('date')
->orderBy('date', 'DESC');
// Fetch records
$records = $query->get();
But now I would like to have only the last record for each day of a customer specified.
I need an eloquent/sql solution because the date range to search may be large and the table has a lot of records.
How can I archive that?
Thanks
Not a complete solution (no customer filter nor laravel use), but I would use something like that in pure sql :
SELECT
CONCAT(EXTRACT(YEAR_MONTH FROM created_at),EXTRACT(DAY FROM created_at)) AS day,
MAX(created_at)
FROM mytable
GROUP BY day;
Of course, you may use other function to group by day (like string regexp or substr).
Related
I Have 4 tables on my db
Table "User"
id | user
-----------
55 | Jhon
56 | Krish
57 | Boss
Table "Payout"
id | Payout_Date
------------------
1 | 31.10.2015
2 | 24.10.2015
3 | 17.10.2015
Table "Earning"
Userid | Date | Earning
------------------------------------
55 | 31.10.2015 | 5$
56 | 31.10.2015 | 1$
57 | 31.10.2015 | 3$
55 | 30.10.2015 | 5$
56 | 30.10.2015 | 12$
57 | 30.10.2015 | 0$
55 | 29.10.2015 | 5$
56 | 29.10.2015 | 4$
When I add a new Payout date (Payout_Date),
I want to find who earn >10$ in their Last payment date between new payout out date, If not pay before that user, his Last Payment_Date is No(get his all earning).
Then add that results to table "Payment" with new Payout_Date to Payment_Date. Their Last Payment_Date is From_Date.
Table "Payment"
id | Userid | From_Date | Payment_Date | Earning | Status
------------------------------------------------------------------
1 | 55 | 24.10.2015 | 31.10.2015 | 12$ | 0
2 | 56 | 24.10.2015 | 31.10.2015 | 17$ | 0
How to write that on Codeigniter Controller and Model?
You need to break the problem down into pieces: find current payout date, find last time user paid, add earnings since then, filter if > $10 .
Here is a sample of what a view may look like (I did not actually run this so there could be syntax errors)
SELECT Earning.Userid, sum(Earning.Earning) earning_since_last
FROM
/* Find current payout Date */
(SELECT MAX(Payout_Date) current_payout_date FROM PAYOUT) as curr_payout,
/* find last time user paid */
(SELECT Userid, MAX(Payout_Date) last_payout_date
FROM PAYOUT
GROUP BY Userid) last_payout,
Earning
WHERE Earning.date <= curr_payout.current_payout_date
and last_payout.Userid = Earning.Userid
and earning.date > last_payout.last_payout_date
GROUP BY Earning.Userid
HAVING SUM(Earning.Earning) >= 10
I have search SO and found answers where people GROUP BY but haven't come across an answer where it displays the ability to GROUP BY (in this case date) and then get the user with the highest # of entries (in each of the date results).
I have my table set up as follows.
+----+------+-----------+-----------------+---------------------+
| id | name | reference | email | date |
+----+------+-----------+-----------------+---------------------+
| 1 | dan | 56453 | dan#example.com | 2015-05-01 09:00:01 |
| 2 | bob | 34564 | bob#example.com | 2015-05-01 09:21:03 |
| 3 | dan | 08948 | dan#example.com | 2015-05-01 09:30:08 |
| 4 | bob | 43775 | bob#example.com | 2015-05-02 09:01:43 |
| 5 | bob | 67210 | bob#example.com | 2015-05-02 09:04:13 |
| 6 | dan | 22195 | dan#example.com | 2015-05-02 09:09:11 |
+----+------+-----------+-----------------+---------------------+
Each day users log in and input a reference. Each day they could be logging many entries.
First, what I'm trying to do is GROUP BY the days and output the data.
So $day[0] which should equal "2015-05-01", should output those first 3 rows and who (and their count) has the highest number of entries for that day.
So output should be:
+----+------+-----------+-----------------+---------------------+
| Results of 2015-05-01 |
+----+------+-----------+-----------------+---------------------+
| 1 | dan | 56453 | dan#example.com | 2015-05-01 09:00:01 |
| 2 | bob | 34564 | bob#example.com | 2015-05-01 09:21:03 |
| 3 | dan | 08948 | dan#example.com | 2015-05-01 09:30:08 |
+----+------+-----------+-----------------+---------------------+
+----+------+-----------+-----------------+---------------------+
| Top user/s for 2015-05-01 |
+-----+-----+---------------------------------------------------+
| dan | 2 | |
+-----+-----+---------------------------------------------------+
So I need to be able to output the data for each day including the user with the most entries for that particular day.
My understanding is that I'd need to do something like this but can't quite grasp it.
$query = mysqli_query('SELECT * FROM mydata GROUP BY DATE(mydata.date as $date)');
$groupcount = 0;
while ($row = #mysqli_fetch_array($query))
{
$rowcount = 0;
$date[$groupcount] = $date;
$dayquery = mysqli_query('SELECT * FROM mydata WHERE date = $date)');
while ($entry = #mysqli_fetch_array($dayquery))
$data[] = array($row['$rowcount']['name'], $row['$rowcount']['reference'], $row['$rowcount']['email'], $row['$rowcount']['date']);
foreach ($data as $d) {
echo "Name: " . $d[0] . ", Reference: " . $d[1] . ", Email: " . $d[2] . ", Date: " . $d[3];
}
$rowcount++;
}
So something like that but also having another query that will output the person and the sum of the highest entries for that day. I just don't want to add another query as I think there would be a better way of structuring this to include COUNT in another.
Could potentially be multiple people with the same number of entries for the day so I'm trying to accommodate for that.
This should give you what you are looking for all in one query.
SELECT
max(m.id), -- since this column is unique you can ignore it if it's not important, or using min/max to get one of the values
max(m.reference), -- since this column appears to be unique you can ignore it if it's not important, or using min/max to get one of the values
m.name,
m.email,
cast(m.date as date) date,
count(*) count
FROM
mydata m
GROUP BY
m.name,
m.email,
cast(m.date as date)
ORDER BY
m.date DESC,
m.count DESC,
m.name ASC,
m.email ASC;
I have a table named nca and heres what it looks like with values :
+--------+---------+------------+------------+--------------+---------+
| nca_id | nca_no | issue_date | nca_amount | account_type | balance |
+--------+---------+------------+------------+--------------+---------+
| 1 | 14-0001 | 2015-01-08 | 200000 | ROP | 0 |
| 2 | 14-0002 | 2015-01-08 | 400000 | ROP | 0 |
| 3 | 14-0003 | 2015-02-02 | 1000000 | ROP | 0 |
| 4 | 14-0004 | 2015-02-02 | 300000 | ROP | 0 |
| 5 | 14-0001 | 2015-01-08 | 250000 | DBP-TRUST | 0 |
| 6 | 14-0002 | 2015-01-08 | 400000 | DBP-TRUST | 0 |
+--------+---------+------------+------------+--------------+---------+
Now using this query it can display the SUM of the nca_amount base on the issue_date:
SELECT SUM(nca_amount) FROM nca WHERE account_type = 'ROP' AND issue_date = '2015-02-02'
which gives a result of 1300000 since it adds all the amount that having a date of 2015-02-02 and just works fine if you set the date just on the query itself.
But I have scenario that I want to solve. I have an html form where the user could enter the date he want.
And if the user would type the date of 2015-02-23, I want this date input referring to the issue_date of 2015-02-02 from my table. What I want is if the date input is in the RANGE of the MONTH of the issue_date on the nca table, this would refer to the issue_date found on the nca table and display the sum. For example :
user input_date = '2015-02-23' referring to issue_date = '2015-02-02'
as the inputted date is in the range of '2015-02-02' found on my nca table and then it can display the sum like on my query above. How can I do this query? Can any one help with this one? thanks in advance.
If you want to match the month:
SELECT SUM(nca_amount)
FROM nca
WHERE account_type = 'ROP' AND
year(issue_date) = year('2015-02-02') and
month(issue_date) = month('2015-02-02');
However, this doesn't allow the query to use an index on issue_date. For that, you need to rephrase the query as:
SELECT SUM(nca_amount)
FROM nca
WHERE account_type = 'ROP' AND
issue_date >= date(concat(left('2015-02-02', 7), '-01')) and
issue_date < date(concat(left('2015-02-02', 7), '-01')) + interval 1 month;
I'm struggling on how to write this query and cant quite find an answer to help me with my case.
Consider the following table:
-----------------------------------------------
| ID | Value1 | Value2 | Value3 | Date |
-----------------------------------------------
| 1 | 10 | 23 | 30 | 2015-01-01 |
-----------------------------------------------
| 1 | 11 | 33 | 40 | 2015-02-01 |
-----------------------------------------------
| 2 | 26 | 93 | 20 | 2015-01-01 |
-----------------------------------------------
| 2 | 11 | 33 | 50 | 2015-02-01 |
-----------------------------------------------
I want to retrieve the average value of Value1 where the Date is 2015-01-01
I thought that
SELECT AVG(PAM_1) FROM MyTable WHERE DATE = 2015-01-01
would work but of course it does not. I'm aware that I probably need to use HAVING but I'm being confused if I must also use GROUP BY and if do I need the AS (something) part.
EDIT
The problem was not related to the query. I was supplying the date trough a variable as such:
$sth = $db->prepare("SELECT AVG(Value1) FROM MyTable WHERE DATE = $date");
Which is not possible to do with prepared statements.
Your query is basically fine. Your date constant is not. Dates constants should be enclosed in single quotes:
SELECT AVG(PAM_1)
FROM MyTable
WHERE DATE = '2015-01-01';
If the date could have a time component, then the following is the best way to handle this:
SELECT AVG(PAM_1)
FROM MyTable
WHERE DATE >= '2015-01-01' AND DATE < '2015-01-02';
I want to write a php script to compare rows from the database and then adds the values together if payment_id are matches. Based on payment_id:
Example:
+----+------------+-----------+--------+
| id | payment_id | cheque_id | amount |
+----+------------+-----------+--------+
| 1 | 1000 | MB101 | 20 |
| 2 | 1000 | MB102 | 20 |
| 3 | 1111 | MB113 | 20 |
+----+------------+-----------+--------+
Result required
+------+--------------+----+
| 1000 | MB101/MB102 | 40 |
| 1111 | MB113 | 20 |
+------+--------------+----+
Trying to merge cheque column as string. For 'Amount' column I know that should be use SUM.
Any suggestions is appreciated,
Thanks
use GROUP BY
select payment_id,group_concat(cheque_id SEPARATOR '/') as cheque_ids,
SUM(amount) as amount
FROM table name
GROUP BY payment_id
I found the solution
SELECT payment_id, group_concat(cheque_id SEPARATOR '/') AS cheque_ids,
SUM(amount) AS amount
FROM tbl_name
GROUP BY payment_id