I have the below code which works:
SELECT admin_teams.name,
SUM(temp_orders.amount_paid) as amount,
SUM(instalments.amount) as amount2
FROM temp_orders
LEFT JOIN admin_teams
ON admin_teams.id = temp_orders.team
LEFT JOIN instalments
ON instalments.order_id = temp_orders.order_id
WHERE
(DATE(temp_orders.date_paid) = CURDATE()
OR DATE(instalments.date_paid) = CURDATE())
AND (temp_orders.pay_status = 4
OR instalments.pay_status = 4)
GROUP BY temp_orders.team
ORDER BY temp_orders.team ASC
LIMIT 5
It produces a table that looks like:
+-------------+--------+---------+
| name | amount | amount2 |
+-------------+--------+---------+
| team name 1 | 100 | 150 |
| team name 2 | 200 | 250 |
| team name 3 | 300 | 175 |
+-------------+--------+---------+
I have two issues;
I actually only want one column which is the sum of amount and amount2.
The query is VERY slow - this took 190 sec to run.
I did have it almost working with a Union which was almost instant - I couldn't however get it fully working because the number of columns in my first select statement will not match those in the second - the table 'instalments' does not have a team column but the table temp_orders does.
Can anyone help with either problem?
Thanks.
SELECT admin_teams.name,
(SUM(temp_orders.amount_paid) + SUM(instalments.amount)) as amount,
FROM temp_orders
LEFT JOIN admin_teams
ON admin_teams.id = temp_orders.team
LEFT JOIN instalments
ON instalments.order_id = temp_orders.order_id
WHERE
temp_orders.date_paid >= CURDATE()
OR instalments.date_paid >= CURDATE())
AND (temp_orders.pay_status = 4
OR instalments.pay_status = 4)
GROUP BY temp_orders.team
ORDER BY temp_orders.team ASC
LIMIT 5
And add these indexes
ALTER TABLE temp_orders ADD KEY (date_paid ,pay_status,team);
ALTER TABLE instalments ADD KEY (date_paid ,pay_status);
Related
table one
id mandal_name
1 mandal1
2 mandal2
3 mandal3
table address
id mandal_name date
1 mandal1 2017-07-11 12:34:11
2 mandal1 2017-07-11 12:54:45
3 mandal1 2017-07-11 12:23:23
SELECT count(id) as yesterday_count, mandal FROM address WHERE date(date) = '2017-07-11'
Result obviously
3 , mandal1
Expecting result
3 , mandal1
0 , mandal2
0 , mandal3
...
The key is to use an OUTER JOIN - LEFT JOIN in this case.
You can either do
SELECT m.mandal_name, COUNT(a.id) AS yesterday_count
FROM table_one m LEFT JOIN address a
ON m.mandal_name = a.mandal_name
AND a.date >= '2017-07-11'
AND a.date < '2017-07-12'
GROUP BY m.mandal_name;
or
SELECT m.mandal_name, COALESCE(count, 0) AS yesterday_count
FROM table_one m LEFT JOIN (
SELECT mandal_name, COUNT(*) AS count
FROM address
WHERE date >= '2017-07-11'
AND date < '2017-07-12'
) a
ON m.mandal_name = a.mandal_name;
Here is a SQLFiddle demo
Output
| mandal_name | yesterday_count |
|-------------|-----------------|
| mandal1 | 3 |
| mandal2 | 0 |
| mandal3 | 0 |
Further reading - A Visual Explanation of SQL Joins
On a side note - don't use DATE(date) as it makes it impossible to use an index on date column effectively causing a full table scan.
you can query it like this:
SELECT A.mandal_name,IFNULL(COUNT(*),0)
FROM one A
LEFT JOIN address B ON A.mandal_name = B.mandal_name
WHERE DATE(B.date) = '2017-07-11'
GROUP BY A.mandal_name
just substitute your table name and columns to get the result
Here is the table ihave, i was trying days between by joining the same table with left join and group by with min difference. I was not so successful.
Customer|Order|Date
1 | 1 |Date1
1 | 2 |Date2
1 | 3 |Date3
1 | 4 |Date4
2 | 1 |Date1
2 | 2 |Date3
2 | 3 |Date6
3 | 1 |Date3
3 | 2 |Date5
Required is:
Customer|Order|Date |diff
1 | 1 |Date1| 0
1 | 2 |Date2| days_betwen(Date2, Date1)
1 | 3 |Date3| days_betwen(Date3, Date2)
1 | 4 |Date4| days_betwen(Date4, Date3)
2 | 1 |Date1| 0
2 | 2 |Date3| days_betwen(Date3, Date1)
2 | 3 |Date6| days_betwen(Date6, Date3)
3 | 1 |Date3| 0
3 | 2 |Date5| days_betwen(Date5, Date3)
I need suggestion with the logic part!
EDIT: What if the order numbers are not sequential?
In first, you need to join the table to itself by Customer and Order fields. Then use DATEDIFF() function to get days number between two dates.
If the Order column is numbered sequentially then solution is simplest:
SELECT
cur.`Customer` AS `Customer`,
cur.`Order` AS `Order`,
cur.`Date` AS `Date`,
DATEDIFF(cur.`Date`, IFNULL(prv.`Date`, cur.`Date`)) AS `DaysPassed`
FROM
MyTable cur
LEFT JOIN
MyTable prv
ON cur.`Customer` = prv.`Customer` AND cur.`Order` = prv.`Order`+ 1;
If the Order column is not numbered sequentially, but next Order value is greater than previous, then you could use greater than or less than operators. Use GROUP BY clause and an aggregate function to return single row for each order. Note, maybe it will be long!
SELECT
comb.`Customer` AS `Customer`,
comb.`curOrder` AS `Order`,
comb.`curDate` AS `Date`,
DATEDIFF(comb.`curDate`, IFNULL(pr.`Date`, comb.`curDate`)) AS `DaysPassed`
FROM
(SELECT
cur.`Customer` AS `Customer`, cur.`Order` AS curOrder, cur.`curDate` AS `Date`, max(prv.`Order`) AS `prvOrder`
FROM
MyTable cur
LEFT JOIN
MyTable prv
ON cur.`Customer` = prv.`Customer` AND cur.`Order` > prv.`Order`
GROUP BY cur.`Order`, cur.`Customer`) comb
LEFT JOIN
MyTable pr
ON pr.`Customer` = comb.`Customer` AND pr.`Order` = comb.prvOrder;
If you use random order number, then it is possible to use Date column instead of Order in the comb subquery to join records by nearest order dates of same customer.
Good luck!
Oh, my title is not the best one and as English is not my main language maybe someone can fix that instead of downvoting if they've understood the issue here.
Basically i have two tables - tourneyplayers and results. Tourneyplayers is like a side table which gathers together tournament information across multiple tables - results, tournaments, players etc. I want to check duplicates from the results table over column day1_best, from single tournament and return all the tourneyplayers who have duplicates.
Tourneyplayers contain rows:
Tourneyplayers
tp_id | resultid | tourneyid
1 | 2 | 91
2 | 21 | 91
3 | 29 | 91
4 | 1 | 91
5 | 3 | 92
Results contains rows:
Results:
r_id | day1_best
1 | 3
2 | 1
3 | 4
.. | ..
21 | 1
.. | ..
29 | 2
Now tourney with id = 91 has in total 4 results, with id's 1,2,21 and 29. I want to return values which have duplicates, so currently the result would be
Result
tp_id | resultid | day1_best
1 | 2 | 1
2 | 21 | 1
I tried writing something like this:
SELECT *
FROM tourneyplayers
WHERE resultid
IN (
SELECT r1.r_id
FROM results AS r1
INNER JOIN results AS r2 ON ( r1.day1_best = r2.day1_best )
AND (
r1.r_id <> r2.r_id
)
)
AND tourneyid =91
But in addition to values which had the same day1_best it chose two more which did not have the same. How could i improve my SQL or rewrite it?
First you JOIN both tables, so you know how the data looks like.
SELECT *
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`;
Then using the same query you GROUP to see what tourneyid, day1_best combination has multiple rows
SELECT `tourneyid`, `day1_best`, count(*) as total
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
GROUP BY `tourneyid`, `day1_best`;
Finally you use the base JOIN and perform a LEFT JOIN to see what rows has a match and show only those rows.
SELECT t.`tp_id`, r.`r_id`, r.`day1_best`
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
LEFT JOIN (SELECT `tourneyid`, `day1_best`, count(*) as total
FROM tourney_players t
JOIN results r
ON t.`resultid` = r.`r_id`
GROUP BY `tourneyid`, `day1_best`
HAVING count(*) > 1) as filter
ON t.`tourneyid` = filter.`tourneyid`
AND r.`day1_best` = filter.`day1_best`
WHERE filter.`tourneyid` IS NOT NULL;
SQL DEMO
OUTPUT
Please try this :
Select tp.tp_id , tp.resultid ,r.day1_best from (Select * from Tourneyplayers
where tourneyid = 91)as tp inner join (select * from Result day1_best in(select
day1_best from result group by day1_best having count(*)>1 ) )as r on tp.resultid
= r.r_id ;
I have two tables looking like this
Patient (table 1)
id | name
------------
1 | robel
2 | dave
Patient_followup (table 2)
id | Patient_id | date_created
-----------------------
1 | ---- 1 -- | 01/01/2015
2 | -----1 -- | 01/07/2016
I want to display all the patients with their perspective latest followup data. so i tried using this query
Select * from patient
left join Patient_followup pf on pf.Patient_id = patient.id
order by pf.date_created
Limit 1
but this is giving me only the first patient robel. i tryed removing the limit and its giving me two records of robel and one record of dave because robel has two followup data. so what should i do to get only one record of each patient ?
Try this:
Select
*
from
patient
left join
(SELECT
id as pf_id,
MAX(date_created) as latest_followup_date,
Patient_id
FROM
Patient_followup
GROUP BY
Patient_id) as pf
ON pf.Patient_id = patient.id
As mentioned by anton in the first comment, you need to use aggregation to get one record per patient.
Select patient.*,MAX(pf.date_created) as followupdate,group_concat(pf.date_created) from patient
left join Patient_followup pf on pf.Patient_id = p.patient.id
group by patient.id
order by pf.date_created
Here, you will get your values comma separated.
1) "Limit 1" will only return the first result. Typically this is used if the query will result in a very large result set and you only want the first few results.
Ex:
"LIMIT 30" will show the first 30 rows of the query.
2) I would change to setup of the tables so the query is smoother. Right now, you create a new line for each follow-up date even if the patient is already created. You could add another column in the table named "FollowUpDate". That way each patient record has the table id, patient id, creation date and followup date in the same row. That way, each patient has only one row.
EX:
Patient (table 1)
id | name | created_date | next_followup_date |
1 | Robel | 01/01/2015 | 01/01/2016 |
2 | Dave |[created_date]| [next_follup_date] |
Patient_followup (table 2)
id | Patient_id | date_created | followUpDate |
1 | 1 | 01/01/2015 | 06/01/2016 | // example date
2 | 1 | 01/01/2015 | 01/01/2016 |
3 | 2 |[date created]| [FollowUpDate] |
3) Change query to:
Use this select statement to get all patient records.
Select * from patient
left join Patient_followup pf on pf.Patient_id = patient.id
order by pf.Patient_id
Use this select statement to get the specific patient record information.
Select * from patient
inner join Patient_followup pf on pf.Patient_id = patient.id
where patient.id = 1 //to get robel. Edit this line as necessary, perhaps by user input...
order by pf.followUpDate
NOTE: When you insert a new record in Patient_followup, make sure you update Patient.next_followup_date.
I hope this helps!
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