This is where I have reached after trying my best
select 13c_name,13c_mobile,13c_pid,p.13c_usid,p.13c_comp_id,13c_amount,
13c_mode,13c_month,13c_year,13c_rec,13c_rec_date,13c_check,13c_comments,
13c_status,13c_ip,13c_message,13c_rec_by,13c_invoice_pay from
13c_users u , 13c_payments p
where ( (u.13c_usid=p.13c_usid and 13c_subs='1') and (13c_year IN ('$new_year') and 13c_month NOT IN (1|2|3|4) or 13) )
What I want to achieve is something like this
I want to select all the members from 13c_users who have subscribed
(13c_subs='1') to monthly payments from table 13c_payments who may not
have paid any of the month of any year till now (13c_month stores the
month number and 13c_year stores the year number in 13c_payment table)
Now above query works some what nice but it does not select the users who have not paid anything yet, like of the user is subscribed and have not paid for any month the query will not match the join tbale with him.
Please check the query what I am doing wrong here!
////////////////////////////////// EDITED ///////////////////
This is until so far I could reach still I am not getting expected results:
select * from ( (select * from 13c_users u Left JOIN 13c_payments p ON
u.13c_usid=p.13c_usid where (13c_subs='1' and u.13c_comp_id='$yid') ) as T )
where ( (13c_year is NULL or 13c_year IN (2019) ) and (13c_month IS NULL or
13c_month NOT IN (1,2,3,4,5,6,7,8,9,10,11,12)) and (T.13c_invoice_pay='0' or T.13c_invoice_pay is
NULL ))
The above query, selects all the members who have never paid but not those members who have paid for the first 2 months and not after that.
Table payment gets the entry of every payment made in separate rows.
I know there is something wrong in this part of query for sure
(13c_year is NULL or 13c_year IN (2019) ) and (13c_month IS NULL or
13c_month NOT IN (1,2,3,4,5,6,7,8,9,10,11,12)
I want to select the row if the row does not have any of the month as mentioned there 13c_month NOT IN (1,2,3,4,5,6,7,8,9,10,11,12) but the rows are separate so it will always select every row
User table
Payments Table
Here's a much simplified example where I work out the number of expected payments and the number of months in which payment has been made - if not the same then I am interested
drop table if exists u,t;
create table u (id int,subs int, dt date);
create table t (uid int,dt date);
insert into u values (1,1,'2019-01-01'),(2,1,'2018-11-01'),(3,1,'2018-09-01');
insert into t values
(1,'2019-01-01'),
(2,'2018-11-11'),(2,'2018-11-13'),(2,'2019-01-01');
select id,
((year(now()) * 12 + month(Now())) - (year(u.dt) * 12 + month(u.dt))) + 1 numexpected,
coalesce(s.paidup,0) paidup
from u
left join
(select t.uid,count(distinct year(t.dt),month(t.dt)) paidup
from t
group by t.uid) s on s.uid = u.id
where ((year(now()) * 12 + month(Now())) - (year(u.dt) * 12 + month(u.dt))) + 1 <> coalesce(s.paidup,0);
+------+-------------+--------+
| id | numexpected | paidup |
+------+-------------+--------+
| 2 | 3 | 2 |
| 3 | 5 | 0 |
+------+-------------+--------+
2 rows in set (0.00 sec)
Note the expectation that a payment should be made every month seems a bit simplistic - what about pre-payments and late payments? For example UID 2 has made 3 payments but 2 were in the same month.
Related
I would like to count how many new unique users the database gets each day for all days recorded.
There will not be any duplicate ids per day, but there will be duplicates over multiple days.
If my table looks like this :
ID | DATE
---------
1 | 2022-05-21
1 | 2022-05-22
2 | 2022-05-22
1 | 2022-05-23
2 | 2022-05-23
1 | 2022-05-24
2 | 2022-05-24
3 | 2022-05-24
I would like the results to look like this :
DATE | NEW UNIQUE IDs
---------------------------
2022-05-21 | 1
2022-05-22 | 1
2022-05-23 | 0
2022-05-24 | 1
A query such as :
SELECT `date` , COUNT( DISTINCT id)
FROM tbl
GROUP BY DATE( `date` )
Will return the count per day and will not take into account previous days.
Any assistance would be appreciated.
Edit : Using MySQL 8
The user is new when the date is the least date for this user.
So you need in something like
SELECT date, COUNT(new_users.id)
FROM calendar
LEFT JOIN ( SELECT id, MIN(date) date
FROM test
GROUP BY id ) new_users USING (date)
GROUP BY date
calendar is either static or dynamically generated table with needed dates list. It can be even SELECT DISTINCT date FROM test subquery.
Start with a subquery showing the earliest date where each id appears.
SELECT MIN(`date`) `firstdate`, id
FROM tbl
GROUP BY id
Then do your count on that subquery. here.
SELECT firstdate, COUNT(*)
FROM (
SELECT MIN(`date`) `firstdate`, id
FROM tbl
GROUP BY id
) m
GROUP BY firstdate
That gives you what you want.
But it doesn't have rows for the dates where no new user ids first appeared.
Only count (and sum) the rows where the left join fails:
SELECT
m1.`DATE` ,
sum(CASE WHEN m2.id is null THEN 1 ELSE 0 END) as C
FROM mytable m1
LEFT JOIN mytable m2 ON m2.`DATE`<m1.`DATE` AND m2.ID=m1.ID
GROUP BY m1.`DATE`
see: DBFIDDLE
I want to fetch data from two tables post, post_like
I want the data such that if row entry is not present in post_like table null/0 as result to be shown
currently row data is omitted if the data is not present for a particular day.
I have prepared sample data
CREATE TABLE post(post_id INT, user_id INT, post_type INT);
INSERT INTO post VALUES (1,1,1),(2,1,2),(3,1,2),(4,2,1),(5,2,3);
CREATE TABLE post_like(post_id INT, user_id INT, created_on DATE);
INSERT INTO post_like VALUES
(1,4,"2020-02-10"),(2,4,"2020-02-10"),
(3,4,"2020-02-10"),(1,4,"2020-02-11"),
(2,4,"2020-02-11"),(3,4,"2020-02-11"),
(1,4,"2020-02-12"),(2,4,"2020-02-13"),
(3,4,"2020-02-13"),(1,4,"2020-02-14"),
(2,4,"2020-02-14"),(3,4,"2020-02-16"),
(1,4,"2020-02-16"),(2,4,"2020-02-16"),
(3,4,"2020-02-17"),(4,4,"2020-02-10"),
(5,4,"2020-02-16"),(4,4,"2020-02-10"),
(4,4,"2020-02-15"),(4,4,"2020-02-13"),
(5,4,"2020-02-11");
SQL fiddle
Query I am using
SELECT COUNT(a.post_id) AS likeCnt
, DAYNAME(DATE(a.created_on)) as day
FROM post_like a
JOIN post b
ON b.post_id = a.post_id
WHERE a.created_on BETWEEN subdate(curdate(),dayofweek(curdate())+5) AND
subdate(curdate(),dayofweek(curdate())-1)
AND b.user_id = 1
AND b.post_type = 2
GROUP
BY DATE(a.created_on)
above query returns me day wise data and total count of rows present in post_like table for that particular day but is omitting result for a day if no entry is found
I want to get the count for that day to be zero instead of skipping it.
Desired Output Example
likeCnt | day
------------------------
4 | Monday
2 | Tueday
1 | Wednesday
0 | Thursday
1 | Friday
1 | Saturday
0 | Sunday
SELECT COALESCE(data.likeCnt, 0) likeCnt,
day_names.day
FROM ( SELECT DAYNAME('2000-01-01') AS day UNION ALL -- generate daynames list
SELECT DAYNAME('2000-01-02') UNION ALL
SELECT DAYNAME('2000-01-03') UNION ALL
SELECT DAYNAME('2000-01-04') UNION ALL
SELECT DAYNAME('2000-01-05') UNION ALL
SELECT DAYNAME('2000-01-06') UNION ALL
SELECT DAYNAME('2000-01-07') ) day_names
LEFT JOIN ( SELECT COUNT(a.post_id) AS likeCnt -- and join the data
, ANY_VALUE(DAYNAME(DATE(a.created_on))) as day
FROM post_like a
JOIN post b ON b.post_id = a.post_id
WHERE a.created_on BETWEEN subdate(curdate(),dayofweek(curdate())+5)
AND subdate(curdate(),dayofweek(curdate())-1)
AND b.user_id = 1
AND b.post_type = 2
GROUP BY DATE(a.created_on) ) data USING (day)
PS. ANY_VALUE() added for possible ONLY_FULL_GROUP_BY SQL mode.
I want to fetch data from two table and apply arithmetic operation on the column.
This is wha I tried :
String sql = "SELECT SUM(S.san_recover-C.amount) as total
FROM sanction S
LEFT JOIN collection C ON S.client_id = C.client_id
WHERE S.client_id=?";
This code is working only when there is value in both tables, but if there is no value in one of two tables there is no result.
SELECT SUM(S.san_recover - C.amount) as total
FROM sanction S
LEFT JOIN collection C ON S.client_id = C.client_id
WHERE S.client_id = ?
The problem with your query lies in the SUM() function. When the left join does not bring back records, then c.amount is NULL. When substracting NULL from something, you get a NULL result, which then propagates across the computation, and you end up with a NULL result for the SUM().
You probably want COALESCE(), like so:
SELECT SUM(S.san_recover - COALESCE(C.amount, 0)) as total
FROM sanction S
LEFT JOIN collection C ON S.client_id = C.client_id
WHERE S.client_id = ?
Where there is a possibility that a client may exist in one table but no another a full join would be appropriate but since mysql does not have such a thing then a union in a sub query will do
drop table if exists sanctions,collections;
create table sanctions(client_id int, amount int);
create table collections(client_id int, amount int);
insert into sanctions values
(1,10),(1,10),(2,10);
insert into collections values
(1,5),(3,10);
Select sum(Samount - camount)
From
(Select sum(amount) Samount, 0 as camount from sanctions where client_id =3
Union all
Select 0,sum(amount) as camount from collections where client_id =3
) s
;
+------------------------+
| sum(Samount - camount) |
+------------------------+
| -10 |
+------------------------+
1 row in set (0.00 sec)
If you want to do this for all clients
Select client_id,sum(Samount - camount) net
From
(Select client_id,sum(amount) Samount, 0 as camount from sanctions group by client_id
Union all
Select client_id,0,sum(amount) as camount from collections group by client_id
) s
group by client_id
;
+-----------+------+
| client_id | net |
+-----------+------+
| 1 | 15 |
| 2 | 10 |
| 3 | -10 |
+-----------+------+
3 rows in set (0.00 sec)
I have two tables:
booking - records the order detail
id | booking_amount
-------------------
1 | 150
2 | 500
3 | 400
payment - records the payment for order
id | booking_id | amount
------------------------
1 | 1 | 100
2 | 1 | 50
2 | 2 | 100
I want to find all bookings where the payments are not complete. With the above data, we expect the answer to be 2,3, because the sum of payments for booking_id=1 matches the corresponding booking_amount in the booking_table.
To answer your question, you have 2 things you need to think about :
you want the total amount in your table payment by every booking row
you want to join your booking_amount table with payment.
Part 1 is quite simple:
SELECT sum(amount) as TotalP, booking_id FROM payment GROUP BY booking_id
Just a basic query with a simple aggregate function...
For part 2, we want to join booking_amount and payment; the basic JOIN would be:
SELECT * FROM booking b
LEFT JOIN payment p ON b.id = p.booking_id
We do a LEFT JOIN because we may have some booking who are not in the payment table. For those bookings, you will get NULL value. We will use a COALESCE to replace the NULL values by 0.
The final query is this:
SELECT b.id, COALESCE(TotalP, 0), b.booking_amount
FROM
booking b
LEFT JOIN
(SELECT sum(amount) as TotalP, booking_id FROM payment GROUP BY booking_id) as T
ON b.id = T.booking_id
WHERE COALESCE(TotalP, 0) < b.booking_amount
You need to use a outer join to combine your two tables and look for your conditions. Also, you will need to use SUM(..) function to get the sum of the amount for each id in the payment table.
Please try this:
select b.id from booking b
left outer join -- cant be inner join because we lose id:3 in that case.
(
select booking_id, SUM(amount) as Total
from payment group by booking_id
) p on b.id = p.booking_id
where b.booking_amount > Coalesce(Total,0) --Coalesce is required for such values coming NULL, like id:3, they will be assigned as 0.
Good day,
I have a MySQL table which has some duplicate rows that have to be removed while adding a value from one column in the duplicated rows to the original.
The problem was caused when another column had the wrong values and that is now fixed but it left the balances split among different rows which have to be added together. The newer rows that were added must then be removed.
In this example, the userid column determines if they are duplicates (or triplicates). userid 6 is duplicated and userid 3 is triplicated.
As an example for userid 3 it has to add up all balances from rows 3, 11 and 13 and has to put that total into row 3 and then remove rows 11 and 13. The balance columns of both of those have to be added together into the original, lower ID row and the newer, higher ID rows must be removed.
ID | balance | userid
---------------------
1 | 10 | 1
2 | 15 | 2
3 | 300 | 3
4 | 80 | 4
5 | 0 | 5
6 | 65 | 6
7 | 178 | 7
8 | 201 | 8
9 | 92 | 9
10 | 0 | 10
11 | 140 | 3
12 | 46 | 6
13 | 30 | 3
I hope that is clear enough and that I have provided enough info. Thanks =)
Two steps.
1. Update:
UPDATE
tableX AS t
JOIN
( SELECT userid
, MIN(id) AS min_id
, SUM(balance) AS sum_balance
FROM tableX
GROUP BY userid
) AS c
ON t.userid = c.userid
SET
t.balance = CASE WHEN t.id = c.min_id
THEN c.sum_balance
ELSE 0
END ;
2. Remove the extra rows:
DELETE t
FROM
tableX AS t
JOIN
( SELECT userid
, MIN(id) AS min_id
FROM tableX
GROUP BY userid
) AS c
ON t.userid = c.userid
AND t.id > c.min_id
WHERE
t.balance = 0 ;
Once you have this solved, it would be good to add a UNIQUE constraint on userid as it seems you want to be storing the balance for each user here. That will avoid any duplicates in the future. You could also remove the (useless?) id column.
SELECT SUM(balance)
FROM your_table
GROUP BY userid
Should work, but the comment saying fix the table is really the best approach.
You can create a table with the same structure and transfer the data to it with this query
insert into newPriceTable(id, userid, balance)
select u.id, p.userid, sum(balance) as summation
from price p
join (
select userid, min(id) as id from price group by userid
) u ON p.userid = u.userid
group by p.userid
Play around the query here: http://sqlfiddle.com/#!2/4bb58/2
Work is mainly done in MSSQL but you should be able to convert the syntax.
Using a GROUP BY UserID you can SUM() the Balance, join that back to your main table to update the balance across all the duplicates. Finally you can use RANK() to order your duplicate Userids and preserve only the earliest values.
I'd select all this into a new table and if it looks good, deprecate your old table and rename then new one.
http://sqlfiddle.com/#!3/068ee/2