query for balance due and due date for entity - mysql

I am trying to get a list of guests who have not yet fully paid their total charges (those who still have a balance).
I want to display like so:
1231231(reservation id) - John Doe(guest name) 2013-11-17(date due) 153.14(balance due)
without the ( ) of course.
I have tinkered but still can't find a query that is satisfactory.
Here is a link to the SQLFiddle.
If I haven't provided enough info, kindly let me know.

Are you looking for something like this?
SELECT r.id,
CONCAT(g.fname, ' ', g.lname) guest_name,
r.arrival date_due,
r.total_price - COALESCE(p.payment_amt, 0) balance_due
FROM reservations r JOIN guests g
ON r.guest = g.id LEFT JOIN
(
SELECT reservation, SUM(payment_amt) payment_amt
FROM payments
GROUP BY reservation
) p
ON r.id = p.reservation
HAVING balance_due > 0
Sample output (based on provided sample data):
| ID | GUEST_NAME | DATE_DUE | BALANCE_DUE |
|---------|------------|---------------------------------|-------------|
| 1000023 | John Doe | November, 09 2013 00:00:00+0000 | 40.5 |
| 1000022 | John Doe | November, 09 2013 00:00:00+0000 | 40.5 |
| 1000018 | John Doe | November, 01 2013 00:00:00+0000 | 54 |
| 1000019 | John Doe | November, 08 2013 00:00:00+0000 | 54 |
| 1000020 | Mary Jane | November, 08 2013 00:00:00+0000 | 54 |
| 1000021 | Mary Jane | November, 08 2013 00:00:00+0000 | 54 |
Here is SQLFiddle demo

Related

How to JOIN a table based on month

I am trying to get the number of appointments for each month.
The results are grouped into each month for a rolling-12-months graph.
I have the following Query:
SELECT a.time AS appointmentdatetime,
m.text AS ref_month_text,
m.month AS ref_month_int,
YEAR(TIME) AS appointmentyear,
COUNT(a.id) AS COUNT
FROM ref_months m LEFT JOIN
appointment a
ON m.month = MONTH(a.time) AND
a.time >= DATE_ADD(NOW(), INTERVAL - 12 MONTH)
AND a.dealershipid = '1' AND a.dealerstatus != 'No-Show'
GROUP BY m.month
ORDER BY appointmentyear ASC, m.month ASC
This is the result:
+----------------+--------------------+-------+--+
| ref_month_text | appointmentyear | COUNT | |
+----------------+--------------------+-------+--+
| February | 2019 | 16 | |
| March | 2019 | 18 | |
| April | 2019 | 10 | |
| May | 2019 | 15 | |
| June | 2019 | 18 | |
| July | 2019 | 10 | |
| August | 2019 | 12 | |
| September | 2019 | 20 | |
| October | 2019 | 7 | |
| November | 2019 | 13 | |
| December | 2019 | 7 | |
| January | 2020 | 11 | |
+----------------+--------------------+-------+--+
The grouping by month, on a rolling-12-months, and showing null when no data, is what I am getting, but the issue I am having is that the count is wrong for each month.
Eg. March 2019 should be 20.
I have tried all variations of JOIN types. But still returning wrong figures.
I simplified your query
SELECT
YEAR(a.time) AS year,
ANY_VALUE(MONTHNAME(a.time)) AS month,
ANY_VALUE(COUNT(a.id)) AS counter,
MONTH(a.time) AS mo
FROM
appointment AS a
GROUP BY
year,mo
ORDER BY
year ASC,
mo ASC

displaying available time by comparing 2 tables with a POST variable

these are my tables
RESERVATIONS
+--------+--------------------+-----------------+
| id | reservation_date | reservation_time|
+--------+--------------------+-----------------+
| 1 | November 05, 2019 | 9:00am-12:00pm |
| 2 | November 05, 2019 | 12:00pm-3:00pm |
| 3 | November 05, 2019 | 3:00pm-6:00pm |
| 4 | November 05, 2019 | 6:00pm-9:00pm |
| 5 | November 06, 2019 | 9:00am-12:00pm |
| 6 | November 06, 2019 | 12:00pm-3:00pm |
| 7 | November 06, 2019 | 3:00pm-6:00pm |
| 8 | November 12, 2019 | 9:00am-12:00pm |
| 9 | November 13, 2019 | 9:00am-12:00pm |
+--------+--------------------+-----------------+
reservation_date is in VARCHAR format
TIME_AVAILABILITY
+--------+------------------+
| id | reservation_time |
+--------+------------------+
| 1 | 9:00am-12:00pm |
| 2 | 12:00pm-3:00pm |
| 3 | 3:00pm-6:00pm |
| 4 | 6:00pm-9:00pm |
+--------+------------------+
so here's the thing, I want to display the values in my TIME_AVAILABILITY table based on a $_POST variable and RESERVATIONS table. For example if a user's input is November 05, 2019 It will display nothing because all the values in TIME_AVAILABILITY table are already in the RESERVATIONS table, but if the user input is November 06, 2019 it will only display 6:00pm-9:00pm
I tried using INNER JOIN but I just can't make it work
The TIME_AVAILABILITY table joined to a subquery of the RESERVATIONS table will produce only the null matches (which is what you are looking for since null represents a TIME_AVAILABILITY that has not been filled for the date put in the where clause your "POST" date as it were):
select t.reservation_time
from TIME_AVAILABILITY t
left join (
select reservation_time, reservation_date
from RESERVATIONS
where reservation_date = 'November 05, 2019'
) as q
on t.reservation_time = q.reservation_time
where q.reservation_date is null;
Alternative to above answer you can do it with not in clause.
select t.reservation_time
from TIME_AVAILABILITY t where t.reservation_time not in (
select reservation_time
from RESERVATIONS
where reservation_date = 'November 05, 2019'
)

Group-by data based on conditions

I will be getting some data which I need to filter out based on some conditions. Sample data:
Cust_ID Date Result
1 2013-08-15 On hold
2 2013-08-16 NULL
3 2013-08-18 WIP
1 2013-08-20 Completed
3 2013-08-25 NULL
4 2013-08-28 NULL
4 2013-08-29 NULL
Conditions:
Fetch the distinct Cust_ID, based on latest Date.(i.e Max(Date))
If the Result is Null for latest Date then get the latest record with any other Result apart from NULL.
If the Result is NULL for all the records with same Cust_ID, pick the latest one based on Date
The desired output should be:
Cust_ID Date Result
1 2013-08-20 Completed
2 2013-08-16 NULL
3 2013-08-18 WIP
4 2013-08-29 NULL
Please advise.
You can do it easy with a CTE, note the CTE is not "needed" (you could use sub-queries) but I think it makes it clear what you are doing.
WITH NonNull AS
(
SELECT CustID, MAX(Date) as Date
FROM tablename
GROUP BY CustID
WHERE Result is not null
), Others AS
(
SELECT CustID, MAX(Date) as Date
FROM tablename
GROUP BY CustID
WHERE CustID NOT IN (SELECT CustID FROM NonNull)
), AlltogetherNow -- not really needed but clearer
(
SELECT CustID, Date
FROM NonNull
UNION ALL
SELECT CustID, Date
FROM Others
)
SELECT A.CustID, A.Date, J.Results
FROM AlltogetherNow A
JOIN tablename J ON A.CustID = J.CustID AND A.Date = J.Date
First you need an IS NULL indicator on each row:
SQL Fiddle
MS SQL Server 2008 Schema Setup:
CREATE TABLE dbo.Results
([CustID] int, [Date] datetime, [Result] varchar(9))
GO
INSERT INTO dbo.Results
([CustID], [Date], [Result])
VALUES
(1, '2013-08-15 00:00:00', 'On Hold'),
(2, '2013-08-16 00:00:00', NULL),
(3, '2013-08-18 00:00:00', 'WIP'),
(1, '2013-08-20 00:00:00', 'Completed'),
(3, '2013-08-25 00:00:00', NULL),
(4, '2013-08-28 00:00:00', NULL),
(4, '2013-08-29 00:00:00', NULL)
GO
Query 1:
SELECT *,CASE WHEN Result IS NULL THEN 0 ELSE 1 END IsNotNull
FROM dbo.Results
Results:
| CUSTID | DATE | RESULT | ISNOTNULL |
|--------|-------------------------------|-----------|-----------|
| 1 | August, 15 2013 00:00:00+0000 | On Hold | 1 |
| 2 | August, 16 2013 00:00:00+0000 | (null) | 0 |
| 3 | August, 18 2013 00:00:00+0000 | WIP | 1 |
| 1 | August, 20 2013 00:00:00+0000 | Completed | 1 |
| 3 | August, 25 2013 00:00:00+0000 | (null) | 0 |
| 4 | August, 28 2013 00:00:00+0000 | (null) | 0 |
| 4 | August, 29 2013 00:00:00+0000 | (null) | 0 |
Then you need to determine the first NULL row and the first NOT NULL row for each customer. You can use the ROW_NUMBER() function for that. You also need to know for each customer if there are any NOT NULL rows:
Query 2:
SELECT *,
ROW_NUMBER()OVER(PARTITION BY CustID,IsNotNull ORDER BY [Date] DESC) _rn,
COUNT(Result)OVER(PARTITION BY CustID) NotNullCount
FROM(
SELECT *,CASE WHEN Result IS NULL THEN 0 ELSE 1 END IsNotNull
FROM dbo.Results
)X1
Results:
| CUSTID | DATE | RESULT | ISNOTNULL | _RN | NOTNULLCOUNT |
|--------|-------------------------------|-----------|-----------|-----|--------------|
| 1 | August, 20 2013 00:00:00+0000 | Completed | 1 | 1 | 2 |
| 1 | August, 15 2013 00:00:00+0000 | On Hold | 1 | 2 | 2 |
| 2 | August, 16 2013 00:00:00+0000 | (null) | 0 | 1 | 0 |
| 3 | August, 25 2013 00:00:00+0000 | (null) | 0 | 1 | 1 |
| 3 | August, 18 2013 00:00:00+0000 | WIP | 1 | 1 | 1 |
| 4 | August, 29 2013 00:00:00+0000 | (null) | 0 | 1 | 0 |
| 4 | August, 28 2013 00:00:00+0000 | (null) | 0 | 2 | 0 |
Finally you can just filter out the first NOT NULL row if there are any or the first NULL row if there are no NOT NULL rows by using the calculated row number:
Query 3:
SELECT CustID,[Date],Result
FROM(
SELECT *,
ROW_NUMBER()OVER(PARTITION BY CustID,IsNotNull ORDER BY [Date] DESC) _rn,
COUNT(Result)OVER(PARTITION BY CustID) NotNullCount
FROM(
SELECT *,CASE WHEN Result IS NULL THEN 0 ELSE 1 END IsNotNull
FROM dbo.Results
)X1
)X2
WHERE _rn = 1 AND SIGN(NotNullCount) = IsNotNull
Results:
| CUSTID | DATE | RESULT |
|--------|-------------------------------|-----------|
| 1 | August, 20 2013 00:00:00+0000 | Completed |
| 2 | August, 16 2013 00:00:00+0000 | (null) |
| 3 | August, 18 2013 00:00:00+0000 | WIP |
| 4 | August, 29 2013 00:00:00+0000 | (null) |

MySQL delete specified rows from a table when the data from yesterday matches the data from today

I have some data stored in a MySQL table called MyTable like this:
+----------+-----------+---------------------+
| my_id | amount | updated |
+----------+-----------+---------------------+
| 105415 | 81 | 2013-02-13 00:00:00 |
| 105414 | 33 | 2013-02-13 00:00:00 |
| 220801 | 240 | 2013-02-13 00:00:00 |
| 105411 | 118 | 2013-02-13 00:00:00 |
| 105411 | 118 | 2013-02-12 00:00:00 |
| 220801 | 240 | 2013-02-12 00:00:00 |
| 105414 | 33 | 2013-02-11 00:00:00 |
| 105415 | 81 | 2013-02-11 00:00:00 |
+----------+-----------+---------------------+
What I would like to do is delete all the rows from yesterday (2013-02-12) that have the same my_id and amount as today (2013-02-13).
I know how to select all the data from today:
SELECT * FROM 'MyTable' WHERE 'updated' = CURDATE()
I know how to select all the data from yesterday:
SELECT * FROM 'MyTable' WHERE 'updated' = CURDATE()-1
I know the syntax for the DELETE command (DELETE FROM 'MyTable' WHERE...).
How do I delete the rows where the my_id and amount match for yesterday and today?
In the example given, I would want to delete these rows:
| 105411 | 118 | 2013-02-12 00:00:00 |
| 220801 | 240 | 2013-02-12 00:00:00 |
And I would want to keep these rows:
+----------+-----------+---------------------+
| my_id | amount | updated |
+----------+-----------+---------------------+
| 105415 | 81 | 2013-02-13 00:00:00 |
| 105414 | 33 | 2013-02-13 00:00:00 |
| 220801 | 240 | 2013-02-13 00:00:00 |
| 105411 | 118 | 2013-02-13 00:00:00 |
| 105414 | 33 | 2013-02-11 00:00:00 |
| 105415 | 81 | 2013-02-11 00:00:00 |
+----------+-----------+---------------------+
A bit modify from #sgeddes 's answer, I think this a bit more precise to your answer:
Anyways, please give credit as correct answer to #sgeddes 's answer since his answer guided to this:
DELETE t1 FROM MyTable AS t1, MyTable as t2
WHERE t1.updated = CURDATE()-1
AND t2.updated = CURDATE()
AND t2.my_id = t1.my_id
And t2.amount = t1.amount;
If you have a primary key, you can also use this (which is my prefer SQL)
DELETE FROM MyTable
WHERE updated = CURDATE()-1
AND (my_id,amount) in (select my_id,amount
from MyTable
where updated = CURDATE());
Something like this should work:
DELETE M
FROM MyTable M
INNER JOIN MyTable M2 ON
M.My_Id = M2.My_Id AND
M.amount = M2.amount AND
M2.Updated = DATE_ADD(M.Updated, INTERVAL 1 DAY)
Here is the updated Fiddle with your sample data above: http://sqlfiddle.com/#!2/5e288/1
And the Results after the Delete:
MY_ID AMOUNT UPDATED
105415 81 February, 13 2013 00:00:00+0000
105414 33 February, 13 2013 00:00:00+0000
220801 240 February, 13 2013 00:00:00+0000
105411 118 February, 13 2013 00:00:00+0000
105414 33 February, 11 2013 00:00:00+0000
105415 81 February, 11 2013 00:00:00+0000
Good luck.

MySQL change last row of rollup

I am running a query for a report and am using rollup to get a total. One of my columns have a text field that is duplicating at the end. For example:
SELECT * FROM transactions;
transNum | itemid | description | qty
---------------------------------------
01 | 01 | DESC1 | 14
02 | 01 | DESC1 | 05
03 | 01 | DESC1 | 01
04 | 02 | DESC2 | 02
05 | 02 | DESC2 | 01
06 | 02 | DESC2 | 02
07 | 03 | DESC3 | 05
08 | 03 | DESC3 | 06
09 | 03 | DESC3 | 01
SELECT itemid,description,qty FROM transactions GROUP BY id WITH ROLLUP;
itemid | description | qty
----------------------------
01 | DESC1 | 20
02 | DESC2 | 05
03 | DESC3 | 12
| DESC3 | 37
This is a rough example, my actual data consists of multiple tables.
Now, I understand that the DESC3 is getting duplicated because I am not grouping by the description field, but is there any function that can get around this?
Other database engines have a GROUPING function, which is basically what I need but in MySQL.
Thank you for any help
OK, then try this:
SELECT a.itemid, b.description, a.total
FROM
(
SELECT itemid, sum(qty) as total
FROM transactions
GROUP BY itemid WITH ROLLUP
) as a
LEFT JOIN item b ON a.itemid=b.itemid
Assuming you have a table named item with item descriptions keyed on itemid.
From the docs, there's no way of altering the content of the last row.
The result set comes with a NULL value in the 1st column of the rollup row so that you can identify it in your application.
Here's a SQL Fiddle to play with it: http://sqlfiddle.com/#!8/d611d/8
As you see it does repeat the previous description in the rollup row.
use: case when itemid is null then Total