Is it possible to merge 2 rows in 1 in mysql? - mysql

I need to merge multiple rows(2 rows in 1 base on conditions) in my table in one, base on:
same custid and same appdate and price = paid
and have the desire output.
My data now:
tbla
appid custid appdate price paid
1 1 10/10/20 20 null
2 2 10/10/20 10 null
3 1 11/10/20 30 null
4 3 12/10/20 20 null
5 1 13/10/20 20 null
6 1 10/10/20 null 20
7 2 11/10/20 null 10
8 1 11/10/20 null 20
9 3 12/10/20 null 20
10 1 13/10/20 null 20
Derire output:
tblb
appid custid appdate price paid
1 1 10/10/20 20 20 => same custid, same appdate, price=paid
2 2 10/10/20 10 null
3 1 11/10/20 30 null
4 3 12/10/20 20 20 => same custid, same appdate, price=paid
5 1 13/10/20 20 20 => same custid, same appdate, price=paid
7 2 11/10/20 null 10
8 1 11/10/20 null 20
Don't bother with appid.I am going to rebuild appid in the end, by creating a new fresh table.

You seem to want aggregation with a twist:
select min(appid) as appid, custid, appdate,
max(price) as price, max(paid) as paid
from tbla
group by custid, appdate, coalesce(price, paid);
The twist is treating the price/paid as a single column.
Here is a db<>fiddle.
Note that in your sample data, one of paid or price is always NULL. If there are exceptions, then this code might not work. I would suggest that you ask a new question with appropriate sample data and desired results if that is the case.

It looks like simple aggregation does what you want:
select min(appid) as appid, custid, appdate, sum(price) as price, sum(paid) as paid
from mytable
group by custid, appdate

You can use a join with union:
with r as
(select t2.appid t2app, t1.appid, t1.custid, t1.appdate, t1.price, t2.paid from test t1 join test t2 on t1.custid = t2.custid and t1.appdate = t2.appdate and t1.price = t2.paid)
select r.appid, r.custid, r.appdate, r.price, r.paid from r
union
select * from test where not exists (select 1 from r where r.t2app = test.appid) and not exists (select 1 from r where r.appid = test.appid);

Related

How to get the correct sum for two columns using case when

I am working on a program that will track a salespersons sold units, these units can be full deals (1) or half deals (0.5). What I need to do is find a way to get the SUM of the full deals and the half deals grouped by a salespersons ID.
Here is the database structure:
id
salesperson_id
salesperson_two_id
sold_date
1
5
null
2022-07-02
2
3
5
2022-07-18
3
4
null
2022-07-16
4
5
3
2022-07-12
5
3
5
2022-07-17
6
5
null
2022-07-18
I have a query that works if I only want to retrieve the SUM for one salesperson:
SELECT
SUM(case when salesperson_id = 5 and isnull(salesperson_two_id) then 1 end) as fullDeals,
SUM(case when salesperson_id != 5 and salesperson_two_id = 5
or salesperson_id = 5 and salesperson_two_id != 5 then 0.5 end) as halfDeals
FROM sold_logs WHERE MONTH(sold_date) = 07 AND YEAR(sold_date) = 2022;
Output would be as expected:
fullDeals
halfDeals
2
1.5
What I am trying to accomplish is get these results for all salespeople in the table and have no clue how to make it happen. Here is what I am trying to get in the results:
salesperson_id
totalDeals
5
3.5
3
1.5
4
1
I would like the results sorted by totalDeals if at all possible.
Use UNION ALL to get a resultset with all the rows for each salesperson, filter for the month that you want and aggregate:
SELECT salesperson_id,
SUM(CASE WHEN salesperson_two_id IS NULL THEN 1 ELSE 0.5 END) totalDeals
FROM (
SELECT salesperson_id, salesperson_two_id, sold_date FROM sold_logs
UNION ALL
SELECT salesperson_two_id, salesperson_id, sold_date FROM sold_logs WHERE salesperson_two_id IS NOT NULL
) t
WHERE MONTH(sold_date) = 7 AND YEAR(sold_date) = 2022
GROUP BY salesperson_id
ORDER BY totalDeals DESC;
See the demo.

configure query to bring rows which have more than 1 entries

How to get those entries which have more than 1 records?
If it doesn't make sense... let me explain:
From the below table I want to access the sum of the commission of all rows where type is joining and "they have more than 1 entry with same downmem_id".
I have this query but it doesn't consider more entries scenario...
$search = "SELECT sum(commission) as income FROM `$database`.`$memcom` where type='joining'";
Here's the table:
id mem_id commission downmem_id type time
2 1 3250 2 joining 2019-09-22 13:24:40
3 45 500 2 egbvegr new time
4 32 20 2 vnsjkdv other time
5 23 2222 2 vfdvfvf some other time
6 43 42 3 joining time
7 32 353 5 joining time
8 54 35 5 vsdvsdd time
Here's the expected result: it should be the sum of the id no 2, 7 only
ie. 3250+353=whatever.
It shouldn't include id no 6 because it has only 1 row with the same downmem_id.
Please help me to make this query.
Another approach is two levels of aggregation:
select sum(t.commission) income
from (select sum(case when type = 'joining' then commission end) as commission
from t
group by downmem_id
having count(*) > 1
) t;
The main advantage to this approach is that this more readily supports more complex conditions on the other members of each group -- such as at most one "joining" record or both "joining" records and no more than two "vnsjkdv" records.
Use EXISTS:
select sum(t.commission) income
from tablename t
where t.type = 'joining'
and exists (
select 1 from tablename
where id <> t.id and downmem_id = t.downmem_id
)
See the demo.
Results:
| income |
| ----- |
| 3603 |
You can use subquery that will find all downmem_id having more than one occurrence in the table.
SELECT Sum(commission) AS income
FROM tablename
WHERE type = 'joining'
AND downmem_id IN (SELECT downmem_id
FROM tablename t
GROUP BY downmem_id
HAVING Count(id) > 1);
DEMO

group by month returns only April for two tables

Currently I am honestly at loss what I am doing wrong. It is a rather simple query I think.
Tables:
operations:
id processedon clientid
1 2018-01-01 9
2 2018-03-16 9
3 2018-04-21 9
4 2018-04-20 9
5 2018-05-09 9
items:
id operation_id quantity unitprice
1 1 10 2
2 1 5 3
3 2 20 4
4 3 10 2
5 4 8 4
6 4 10 4
7 5 2 2
The expected result of the operation/query is:
month total_value
1 35
3 80
4 92
5 4
That is quantity * unitprice based. For some reason, it only returns month=4
SELECT
month(`operations`.`processedon`) AS `month`,
SUM((`items`.`quantity` * `items`.`unitprice`)) AS `total_value`
FROM `items`
INNER JOIN `operations` ON (`items`.`operation_id` = `operations`.`id`)
GROUP BY 'month'
ORDER BY 'month'
According to the info provided the join should be
INNER JOIN operations ON items.operation_id = operations.id
Eg
SELECT
month(`operations`.`processedon`) AS `month`,
SUM((`items`.`quantity` * `items`.`unitprice`)) AS `total_value`
FROM `items`
INNER JOIN `operations` ON `items`.`operation_id` = `operations`.`id`
GROUP BY month(`operations`.`processedon`)
ORDER BY `month`
There is no efficiency gain by using a column alias in the group by clause, I prefer to avoid using them except perhaps in the order by clause.
The following query will give you the required answer
SELECT
month(`operations`.`processedon`) AS `month`,
SUM((`items`.`quantity` * `items`.`unitprice`)) AS `total_value`
FROM items
INNER JOIN operations ON (items.operation_id = operations.id)
GROUP BY month(operations.processedon)
ORDER BY month(operations.processedon)
You need to specify month correctly since it is not an existing column.
You'll get the following result
month total_value
1 35
3 80
4 92
5 4

latest rate and sum of quantity from mysql table

I have a table look like below:
uid added_on rm_id qnty rate
1 2017-10-23 10:48:50 5 2 30
2 2017-10-23 10:48:50 6 4 70
3 2017-10-23 10:48:50 7 5 10
4 2017-10-24 11:02:10 5 10 28
5 2017-10-24 11:02:10 6 2 75
6 2017-10-24 11:03:37 7 1 15
7 2017-10-25 11:02:10 6 5 65
8 2017-10-25 11:03:37 7 8 12
I need the rm_id , its quantity (that is rm_id 5 is 12(2+10) ), and its last added rate(latest rate can find from the latest added_on rate or from last uid for each rm_id). Any way the result should look like below:
Result
rm_id total_qnty rate
5 12 28
6 11 65
7 14 12
I tried to achieve this by using
SELECT `rm_id`, sum(`qnty`),`rate` FROM `stock` group by `rm_id` having max(`uid`)
and
SELECT `rm_id`, sum(`qnty`),`rate` FROM `stock` group by `rm_id` having max(date(`added_on`))
But not getting the result as desired.. please help me..
You need to locate the max date, and from that determine the rate, and apply that rate to the summed quantity.
select
t.rm_id, t.rate, gd.sum_qty, gd.sum_qty * t.rate
from table1 t
inner join (
select rm_id, max(added_on) max_date, sum(qnty) sum_qty
from table1
group by rm_id
) gd on t.rm_id = gd.rm_id and t.added_on = gd.max_date
The data model is strange, why aren't rates separated?
having max(uid) translates to having 8 for rm_id = 7. And MySQL treats numbers > 0 as true, so this becomes having true, i.e. don't limit my results in any way. The aggregated result doesn't contain the single rates anyway, so it's too late to try to get it via HAVING. You'd need an aggregation function for this, such as Oracle's KEEP LAST, but MySQL doesn't feature this.
What you want instead is to get the maximum uid and with its help select the related record:
select
stock.rm_id,
stockagg.sum_qnty,
stock.rate as last_rate
from
(
select
rm_id,
sum(qnty) as sum_qnty,
max(uid) as max_uid
from stock
group by rm_id
) stockagg
join stock on stock.uid = stockagg.max_uid;
You can use subqueries:
SELECT `rm_id`, sum(`qnty`),
(SELECT `rate`
FROM `stock` s1
WHERE `uid` = (SELECT `uid`
FROM `stock` s2
WHERE s2.`rm_id` = s1.`rm_id`
ORDER BY `added_on` DESC
LIMIT 1)
) AS `rate`
FROM `stock`
GROUP BY `rm_id`

Mysql JOIN with extra priority column

I have two days trying to do this query with no luck.
I have two tables 'DEMAND' and 'DEMAND_STATE' (one to many relation). The table DEMAND_STATE have millions entries.
CREATE TABLE DEMAND
(
ID INT NOT NULL,
DESTINY_ID INT NOT NULL
)
CREATE TABLE DEMAND_STATE
(
ID INT NOT NULL,
PRIORITY INT NOT NULL,
QUANTITY DOUBLE NOT NULL,
CASE_ID INT NOT NULL,
DEMAND_ID INT NOT NULL,
PHASE_ID INT NOT NULL
)
The QUANTITY of the DEMAND_STATE is given according to a CASE_ID and PHASE_ID. We have 'N' PHASES in 'M' CASES. Always the same number of Phases in all Cases. We always have a initial Base Quantity called 'BASE CASE' in the Case with CASE_ID = 1.
For example to obtain quantity for Case (id=2) and Case Base (id=1)
select D.*, S.PRIORITY, S.QUANTITY, S.CASE_ID, S.DEMAND_ID, S.PHASE_ID
FROM DEMAND D
join DEMAND_STATE S on (D.ID = S.DEMAND_ID)
WHERE (S.CASE_ID = 2 OR S.CASE_ID = 1)
(paste only for id=8)
ID PRIORITY QUANTITY CASE_ID DEMAND_ID PHASE_ID
8 0 85 1 8 1
8 0 83 1 8 2
8 0 88 1 8 3
8 0 89 1 8 4
8 10 85 2 8 1
8 10 84 2 8 2
8 10 86 2 8 3
8 10 89 2 8 4
We need to obtain for all Demand in 'DEMAND' only the Quantity for Each Phase with MAX priority. The idea is no duplicate DEMAND_STATE data for each new Case creation. Only create new state rows when Demand-Case-Phase is different to Case Base. This is a new project and we accept changes in model for better performance.
I also tried with the MAX calculation. This query over DEMAND_STATE works fine but only obtain data for a concrete DEMAND_ID. Further i think this solution can be so expensive.
SELECT P.ID, P.QUANTITY, P.CASE_ID, P.DEMAND_ID, P.PHASE_ID
FROM DEMAND_STATE P
JOIN (
SELECT PHASE_ID, MAX(PRIORITY) max_priority, S.DEMAND_ID
from DEMAND_STATE S
WHERE S.DEMAND_ID = 1
AND (S.CASE_ID=1 OR S.CASE_ID=2)
GROUP BY S.PHASE_ID
) SUB
ON (SUB.PHASE_ID = P.PHASE_ID AND SUB.max_priority = P.PRIORITY)
WHERE P.DEMAND_ID = 1
GROUP BY P.PHASE_ID
The result:
ID QUANTITY CASE_ID DEMAND_ID PHASE_ID
1 86 1 1 1
2 85 1 1 2
3 81 1 1 3
8 500 2 1 4
This is the result expected:
ID ID PRIORITY QUANTITY CASE_ID PHASE_ID
8 1 0 86 1 1 (data from Case Base id=1 priority 0)
8 2 10 85 1 2 (data from Case Baseid=1 priority 0)
8 3 10 81 1 3 (data from Case Base id=1 priority 0)
8 64 10 500 2 4 (data from Case id=2 priority 10)
thank for help :)
Edit:
Result of Simon proposal:
ID QUANTITY CASE_ID DEMAND_ID PHASE_ID
1 86 1 1 1
2 85 1 1 2
3 81 1 1 3
4 84 1 1 4 (this row shouldnt exist)
8 500 2 1 4 (this is the correct row)
Also would have to join it with DEMAND
#didierc response:
ID ID MAX(S.PRIORITY) QUANTITY CASE_ID PHASE_ID
1 8 10 500 2 4
2 13 10 81 2 1
2 14 10 83 2 2
2 15 10 84 2 3
3 21 10 81 2 1
4 31 10 86 2 3
4 32 10 80 2 4
4 29 10 85 2 1
4 30 10 81 2 2
we need for each DEMAND four rows with the quantity Value. In Case Base we have four quantity and in Case 2 we only change the quantity for phase 4. We need always four rows for each demand.
Database DEMAND_STATE data:
ID PRIORITY QUANTITY CASE_ID DEMAND_ID PHASE_ID
1 0 86 1 1 1
2 0 85 1 1 2
3 0 81 1 1 3
4 0 84 1 1 4
8 10 500 2 1 4
We need to obtain for all Demand in 'DEMAND' only the Quantity for Each Phase with MAX priority
I translate the above, according to your sample result set, as:
SELECT
D.ID, S.ID, MAX(S.PRIORITY), S.QUANTITY, S.CASE_ID, S.PHASE_ID
FROM DEMAND D
LEFT JOIN DEMAND_STATE S
ON D.ID = S.DEMAND_ID
GROUP BY S.PHASE_ID, S.DEMAND_ID
Update:
To get the maximum priority for each pair(demand_id,phase_id)n we use the following query:
SELECT
DEMAND_ID, PHASE_ID, MAX(PRIORITY) AS PRIORITY
FROM DEMAND_STATE
GROUP BY DEMAND_ID, PHASE_ID
Next, to retrieve the set of phases for a given demand, just make an inner join on demand state:
SELECT S.* FROM DEMAND_STATE S
INNER JOIN (
SELECT
DEMAND_ID, PHASE_ID, MAX(PRIORITY) AS PRIORITY
FROM DEMAND_STATE
GROUP BY DEMAND_ID, PHASE_ID
) S2
USING (DEMAND_ID,PHASE_ID, PRIORITY)
WHERE DEMAND_ID = 1
If you want to limit the possible cases, include a where clause in the query S2:
SELECT S.* FROM DEMAND_STATE S
INNER JOIN (
SELECT
DEMAND_ID, PHASE_ID, MAX(PRIORITY) AS PRIORITY
FROM DEMAND_STATE
WHERE CASE_ID IN (1,2)
GROUP BY DEMAND_ID, PHASE_ID
) S2
USING (DEMAND_ID,PHASE_ID, PRIORITY)
WHERE DEMAND_ID = 1
However, your comments and update indicates that MAX(PRIORITY) does not seem very relevant after all. My understanding is that you have a base case, which may be overriden by another case in a given scenario (that scenario is the pair base case + some other case). Clarify that point in your question body if this is incorrect. If that is the case, you may change the above query by replacing PRIORITY by CASE_ID:
SELECT S.* FROM DEMAND_STATE S
INNER JOIN (
SELECT
DEMAND_ID, PHASE_ID, MAX(CASE_ID) AS CASE_ID
FROM DEMAND_STATE
WHERE CASE_ID IN (1,2)
GROUP BY DEMAND_ID, PHASE_ID
) S2
USING (DEMAND_ID,PHASE_ID, CASE_ID)
WHERE DEMAND_ID = 1
The only reason I see from having a priority is if you wish to combine more than 2 cases, and use priority to select which case will prevail depending on the phase.
You may of course prepend an inner join on DEMAND to include the related demand data.
Use of subqueries should be able to do as you wish, if I understand your question correctly. Something along the lines of the following:
SELECT
P.ID,
P.QUANTITY,
P.CASE_ID,
P.DEMAND_ID,
P.PHASE_ID
FROM DEMAND_STATE P
INNER JOIN (
-- Next level up groups it down and so gets the rows first returned for each PHASE_ID, which is the highest priority due to the subquery
SELECT
D.PHASE_ID,
D.PRIORITY,
D.DEMAND_ID
FROM (
-- Top level query to get all rows and order them in desc priority order
SELECT
S.PHASE_ID,
S.PRIORITY,
S.DEMAND_ID
FROM DEMAND_STATE S
WHERE S.DEMAND_ID IN (1) -- Update this to be whichever DEMAND_IDs you are interested in
AND S.CASE_ID IN (1,2)
ORDER BY
S.PHASE_ID ASC,
S.DEMAND_ID ASC,
S.PRIORITY DESC
) D
GROUP BY
D.PHASE_ID,
S.DEMAND_ID
) SUB
ON SUB.PHASE_ID = P.PHASE_ID
AND SUB.DEMAND_ID = P.DEMAND_ID
The top level subquery exists to get the rows you are interested in and order them in an order which allows predictable results when they are then grouped down by PHASE_ID and DEMAND_ID. This in turn allows a simple INNER JOIN to DEMAND_STATE hopefully (unless I have misunderstood your query)
This may still be expensive though depending on how much data is within that top level query.