MySQL calculate difference in count column between two queries - mysql

I have two different queries. One for "plus" and one for "minus". I want to find the difference in the count value for each player.
I tried union all and got some very weird numbers.
Here are the results of each query which I ned to find the difference of:
fk_plus_player1_id cnt
90 71
65 68
79 66
45 59
64 57
27 56
55 56
93 55
37 55
40 44
1 36
84 33
20 31
24 28
8 23
fk_minus_player1_id cnt
93 44
64 42
79 40
37 35
90 33
20 31
84 31
27 30
65 30
40 26
1 26
24 25
45 25
55 22
8 10
How would I accomplish this? Thanks in advance for your help. I am a noob...
UGH...Trying to do the join method. Having issues, getting no results, just 4 empty columns. This is what I am trying
SELECT
*
FROM
(
SELECT
statement for plus results here
) AS tp
JOIN (
SELECT
statement for minus results here
) AS tm ON tp.fk_plus_player1_id = tm.fk_minus_player1_id
GROUP BY
fk_plus_player1_id
suggestions??

You have two tables.
You want for each player, the difference of the counts.
So :
SELECT t1.fk_minus_player1_id AS player, ABS(t1.cnt - t2.cnt) AS difference
FROM table1 t1, table2 t2
WHERE t1.fk_minus_player1_id = t2.fk_plus_player1_id
GROUP BY t1.fk_minus_player1_id;
Maybe this is what you're looking for ?
WITH query1 AS
(SELECT t1.fk_minus_player1_id AS player, (t1.cnt - IFNULL(t2.cnt,0)) AS difference
FROM table1 t1 LEFT OUTER JOIN table2 t2 ON t1.fk_minus_player1_id = t2.fk_plus_player1_id
GROUP BY t1.fk_minus_player1_id),
query2 AS (SELECT t2.fk_plus_player1_id AS player, (IFNULL(t1.cnt,0) - t2.cnt) AS difference
FROM table2 t2 LEFT OUTER JOIN table1 t1 ON t1.fk_minus_player1_id = t2.fk_plus_player1_id
GROUP BY t2.fk_plus_player1_id)
(SELECT player, difference
FROM query1)
UNION
(SELECT player, difference
FROM query2 WHERE player NOT IN (SELECT player FROM query1))

You run the risk that the same players are not in both lists. The solution is union all with group by:
select player1id, sum(pluscnt) as pluscnt, sum(minuscnt) as minuscnt,
(sum(pluscnt) - sum(minuscnt)) as diff
from ((select player1id, cnt as pluscnt, 0 as minuscnt
from plustable
) union all
(select player1id, 0, cnt
from minustable
)
) t
group by player1id;

Related

MySQL-how to make query for selecting opening recd issued closingbalance rate from two different table one is purchase and another is issued [duplicate]

This question already has answers here:
What's the most efficient way to select the last n rows in a table without changing the table's structure?
(8 answers)
Closed 4 years ago.
I want to make a query that retrieve data from two table i.e one is purchase and another is issue.
both tables have same fields i.e icode,qty,rate,purdate and issuedate.
query of purchase is:-SELECT Dry_Purchase.Icode, Sum(Dry_Purchase.Qty) AS SumOfQty, Dry_Purchase.Rate
FROM Dry_Purchase
WHERE (((Dry_Purchase.PurDate) Between DateSerial(Year(Date()),(Month(Date())-1),21) And DateSerial(Year(Date()),Month(Date()),20)))
GROUP BY Dry_Purchase.Icode, Dry_Purchase.Rate;
output of purchase query is:
Icode SumOfQty Rate
11 10 13.5
11 39.5 14
19 75 79.75
19 22 80
21 54 87.45
23 15 218
24 10.5 650
8 79 33.25
8 13 34
query of issue is :- SELECT Dry_Expense.Icode, Sum(Dry_Expense.Qty) AS SumOfQty, Dry_Expense.Rate
FROM Dry_Expense
WHERE (((Dry_Expense.ExpDate) Between DateSerial(Year(Date()),(Month(Date())-1),21) And DateSerial(Year(Date()),Month(Date()),20)))
GROUP BY Dry_Expense.Icode, Dry_Expense.Rate;
output of this query is
Icode SumOfQty Rate
11 11.55 13
11 8.55 13.5
11 10.8 14
19 2.35 80
21 54 87.45
8 15.9 33.25
after combining above both query the output should like this
rptdate icode opening recd issued closingbal rate
19/09/18 11 0 10 8.550 1.450 13.50
19/09/18 11 0 39.5 10.800 28.700 14.00
19/09/18 19 0 75 0.000 75 79.75
19/09/18 19 0 22 2.350 72.650 80.00
19/09/18 21 0 54 54 0 87.45
19/09/18 23 0 15 0 15 218.00
19/09/18 24 0 10.5 0 10.500 650.00
19/09/18 8 0 79.0 15.900 63.100 33.25
19/09/18 8 0 13.0 0 13.000 34.00
19/09/18 8 11.550 0 11.550 0 13.00
please help me how to make query for this output
i am trying this query
SELECT A.icode,A.qty,A.rate,A.recd as recd,B.Issued as Issue
FROM (SELECT icode,rate,purdate,SUM(Abs(qty)) AS recd
FROM Dry_Purchase GROUP BY icde,rate ) A,
(SELECT icode,rate,expdate,(SUM(Abs(qty)) AS Issue
FROM Dry_Expense GROUP BY icode,rate) B
WHERE A.icode=B.icode AND A.rate=B.rate AND
(A.purdate Between DateSerial((Year(Date()),(Month(Date())-1),21)) And DateSerial(Year(Date()),Month(Date()),20))
AND B.expdate Between DateSerial((Year(Date()),(Month(Date())-1),21) And DateSerial(Year(Date()),Month(Date()),20));
please help me
Use a sub-select to locate the minimum date, then join to the to get the row matching that date.
SELECT
a.`Purdate` AS a.`Date1`, a.`Qty`, a.`Rate`
FROM `TableName` a
JOIN (SELECT MIN(`PurDate`) as `minDate`
FROM `TableName`
WHERE `Icode` = '1') b
ON b.`minDate` = a.`PurDate`
WHERE a.`Icode` = '1'
Since you don't need grouping you can just order by the date column and get the first two rows.
SELECT PurDate, Qty, Rate FROM TableName WHERE Icode = '1' ORDER BY PurDate LIMIT 2
use corelated sub query and union
select A.* from
(
select * from tablename t1 #1st min date will return
where t1.purdate in
(select min(purdate) from
tablename t2 where t2.icode=t1.icode
)
union
select t1.* from tablename t1 inner join
(SELECT
Icode
, Purdate
FROM (
SELECT
#row_num :=IF(#prev_value=Icode,#row_num+1,1) AS rn
, mp.Icode
, mp.Purdate
, #prev_value := Icode
FROM tablename mp
CROSS JOIN (SELECT #row_num :=1, #prev_value :='') vars
ORDER BY
mp.Icode
, mp.Purdate DESC
) d
WHERE rn = 2
) t2
on t1.Icode=t2.Icode and t1.Purdate=t2.Purdate
) as A where A.Icode in (......)

Select corresponding value from second table (Mysql)

Struggling with some sql, would appreciate some guidance.
Have two tables logs and sense
logs –
assetid ts nodeid status
1 2017-10-26 14:00:10 73 240
2 2017-10-26 14:00:06 21 160
3 2017-10-26 14:00:04 18 230
4 2017-10-26 14:00:02 19 400
5 2017-10-26 14:00:00 21 190
1 2017-10-26 13:20:08 18 20
2 2017-10-26 13:06:10 20 160
3 2017-10-26 13:03:04 17 230
sense –
status value
20 5
160 37
190 39
230 56
240 58
400 90
Trying to find the correct syntax to only show the latest record (in datetime) of each assetid and then show the corresponding value from the sense table (based on the matching status in both tables) to produce –
assetid ts nodeid status value
1 2017-10-26 14:00:10 73 240 58
2 2017-10-26 14:00:06 21 160 37
3 2017-10-26 14:00:04 18 230 56
4 2017-10-26 14:00:02 19 400 90
5 2017-10-26 14:00:00 21 190 39
Have tried –
Select assetid, ts, nodeid, status, value
From
logs
Join sense X on X.status = logs.status
Group by assetid
Order by ts DESC
But this only outputs 1 row (instead of 5)
assetid ts nodeid status value
1 2017-10-26 14:00:10 73 240 58
Removing
Join sense X on X.status = logs.status
of course outputs all records but that is not required.
Thoughts appreciated.
Regards
Active
Actually your query is returning 5 rows, 1 for each id. But it won't return rows with latest ts for each id. You can verify this by clicking on the link for demo. You can compare results of both queries.
To achieve this task,following query will help you:
Select l.assetid, l.ts, logs.nodeid, X.status, X.value
From
logs
inner Join sense X on X.status = logs.status
inner join (select assetid, max(ts) as ts from logs group by assetid) l
on l.assetid = logs.assetid and logs.ts = l.ts
Group by l.assetid
Order by l.ts DESC;
Click here for Demo
EDIT:
If dataype of ts is string then replace max(ts) in above query with:
max(str_to_date(ts,'%d%m%y'))
Feel free to ask any doubts.
Hope it helps!
Try this
Select a1.assetid, MAX(a1.ts), a1.nodeid, a1.status, X.value
From
logs a1
inner join sense X on X.status = a1.status
Group by assetid, a1.nodeid, a1.status, X.value
Order by ts DESC
Use GROUP BY to find minimum for each assetid and then JOIN with the logs and sense
Select *
FROM logs l
JOIN sense s ON s.status = l.status
JOIN
(
Select assetid, max(ts) maxts
From logs
Group by assetid
) t ON t.assetid = l.assetid and l.ts = t.maxts
demo
On MY SQL 8.0.2
WITH CTE as
(
Select A.assetid, A.ts, A.nodeid, A.status, B.value, row_number() over(PARTITION BY A.assetid ORDER BY A.ts DESC) AS rn
from logs as A
inner join sense B ON A.status=B.status
)
SELECT *
FROM CTE
WHERE rn='1';

How to properly exclude rows with references to each other?

This question is based on the not very trivial question How to remove two duplicate column. I already suggested solution on that question, but I think there is some more suitable and elegant solution than mine.
There is some table of private messages with columns msg_id, from, to.
And we have this data in it:
msg_id from to
----------------
1 46 0
2 46 18
3 46 50
4 46 39
5 46 11
6 11 46
7 46 12
8 46 56
9 46 11
We need to exclude rows with the conversations, in which there are more than one message (like rows with msg_id = 5, 6 and 9) and in the same time we need to leave first row in output among these rows. In general output should be like this (note: without msg_id = 6 and msg_id = 9):
msg_id from to
----------------
1 46 0
2 46 18
3 46 50
4 46 39
5 46 11
7 46 12
8 46 56
My solution is:
select distinct pm.`from`, pm.`to`
from `tsk_private_message` pm
left join
(select distinct pm.`from`, pm.`to`
from `tsk_private_message` pm
inner join `tsk_private_message` pm2
on (pm.`to` = pm2.`from`) and (pm2.`to` <> pm.`from`)) a
using (`from`, `to`)
where a.`from` is null;
I just search unnecessary rows among these conversations via subquery and "subtract" result from the main table. What do you think? Is there more elegant and more simple solution? I just really don't like this tricky code.
Here is SQL Fiddle
SELECT mx.msg_id, pm.ffrom, pm.tto
FROM tsk_private_message pm
WHERE NOT EXISTS (
SELECT * FROM tsk_private_message nx1
WHERE nx1.ffrom = pm.ffrom AND nx1.tto = pm.tto
AND nx1.msg_id < pm.msg_id
)
AND NOT EXISTS (
SELECT * FROM tsk_private_message nx2
WHERE nx2.ffrom = pm.tto AND nx2.tto = pm.ffrom
AND nx2.msg_id < pm.msg_id
);
Note: I renamed the to and from columns to tto and ffrom, because to and from both are keywords in SQL and I don't like quoting identifiers.
Extra: sqlfiddle (courtesy of Alexander Myshov)
SELECT *
FROM
tsk_private_message INNER JOIN (
SELECT MIN(id) min_id
FROM tsk_private_message
GROUP BY
LEAST(`from`, `to`),
GREATEST(`from`, `to`)) min_msg
ON tsk_private_message.id = min_msg.min_id
ORDER BY
id
Please see fiddle here.

MySQL Query suggestion with access id

I have a MySQL table like this
ownerlisting_access_id property_id mainaccess_id subaccess_id access_value
62 2 35 41 Yes
64 2 35 36 Yes
123 4 35 41 Yes
125 4 35 36 Yes
306 7 35 41 Yes
307 7 35 42 Yes
308 7 35 36 Yes
I want a query that will give me this output using subaccess_id(41,42,36) and mainaccess_id(35) -
ownerlisting_access_id property_id mainaccess_id subaccess_id access_value
306 7 35 41 Yes
307 7 35 42 Yes
308 7 35 36 Yes
I need to get the property_id as 7 using sub access id with 41, 42, 36
The fastest way to get an answer to your question is to describe the PROBLEM not just show results you need. It's not clear what is the logic behind your desired output. I guess you need the rows with the highest property_id for each group subaccess_id. If so here is the query:
select * from t
join (select subaccess_id, max(property_id) MAX_property_id
from t
where mainaccess_id=35
and
subaccess_id in (41,42,36)
group by subaccess_id
) t1
on t.subaccess_id=t1.subaccess_id
and
t.property_id=t1.MAX_property_id
SQLFiddle demo
Also here is a query that outputs results you needed :) But I guess it doesn't solve your PROBLEM:
select * from t where property_id=7
Try this:
SELECT table1.* FROM (
select property_id, group_concat(DISTINCT subaccess_id ORDER BY subaccess_id) as list
from table1 as t1 group by property_id
) a, table1
WHERE a.property_id = table1.property_id
AND a.list = '36,41,42'
Working query: http://sqlfiddle.com/#!2/4744ea/2
SELECT MAX(DISTINCT property_ID) AS property_ID, mainaccess_id,
MAX(DISTINCT subaccess_id) AS subaccess_id, MAX(DISTINCT access_value)
FROM tableName GROUP BY mainaccess_id ORDER BY mainaccess_id
SELECT property_ID, mainaccess_id, subaccess_id, access_value
FROM tableName t1
WHERE t1.mainaccess_id = 35
AND (t1.subaccess_id = 41 OR t1.subaccess_id = 42 OR t1.subaccess_id = 36)
AND t1.property_ID = (SELECT MAX(t2.property_ID)
FROM tableName t2
WHERE t2.mainaccess_id = 35
AND (t2.subaccess_id = 41 OR t2.subaccess_id = 42 OR t2.subaccess_id = 36))

Find repeated battles

I have one table with the following fields:
battle_id, winner, looser
1 200 44
2 55 366
3 44 200
4 123 200
5 200 44
6 55 366
7 177 205
8 188 211
9 366 55
10 55 366
right now it has about 1300 records (its small), and there are about 400 players, in each battle there can only be a winner and a looser (there are no draws)
how can i find all the repeated battles? i do not want to find all the repeated battles of one player, i do want to know all the repeated battles of all the players...i know that i cam make a recursive function in php that iterates over all the battles and assign them to a matrix, but just for fun...is there a way to do it only on mysql?
And how can i optimize the table to find the repeated battles more quickly?
regards
EDIT:
For example i want the query to show:
battle_id, winner, looser
1 200 44
2 55 366
3 44 200
5 200 44
6 55 366
9 366 55
10 55 366
This should work, using a self-join could result in many duplicated entries
SQLFIDDLE
SELECT
t1.battle_id,
t1.winner,
t1.loser
FROM
your_table t1
WHERE
EXISTS (
SELECT
1
FROM
your_table t2
WHERE
( ( t1.winner = t2.winner
AND t1.loser = t2.loser )
OR ( t1.loser = t2.winner
AND t1.winner = t2.loser ) )
AND t1.battle_id <> t2.battle_id
)
try this:
SELECT b1.battle_id,
b1.winner,
b1.looser
FROM battles as b1
group by b1.battle_id, b1.winner, b1.looser
having count(*)>=2