MySQL query row/column difference - mysql

I'm trying to write a MySQL query that does the following:
I have a table that looks like this
Id t
-----------
1 1
2 4
1 6
2 9
1 12
2 14
I need to find the sum of the t column for each Id of 2, and subtract from it the sum of the t column for each Id of 1.
So for this example, the sum of Id 1 is 19, and the sum of Id 2 is 27.
I would want the output to then be 8.
I would imagine the statement would look similar to:
SELECT sum(t) WHERE Id = 2 - sum(t) WHERE Id = 1;
But this obviously isn't proper syntax.
And I apologize for the poorly drawn table, I'm still new to stackoverflow.

You could use a CASE statement:
SELECT
SUM(CASE
WHEN Id = 2 THEN t
WHEN Id = 1 THEN 0 - t
ELSE 0
END) AS mySum
FROM myTable
Hopefully that works as-is... I only have SQL Server to test on, but the syntax should be the same for MySQL.

SELECT SUM(IF(`id` = 2, t, 0)) - SUM(IF(`id` = 1, t, 0)) as `result` FROM `table`

Depends on how big is your table. If it is small or no indexes you can do:
select sum(if( Id=2,t,if(Id=1,-t,0)))
from data;
If you have plenty of rows and have an index in column Id:
select sum(id2)-sum(id1)
from (
select 0 as 'id1', sum(t) as 'id2'
from data
where id=2
union
select sum(t) as 'id1', 0 as 'id2'
from data
where id=1
) as d;

Related

SQL - Get rows where all columns are in a list that have the same value in another column

I have a database as follows:
drinks_id ingredients_master_id
1 2
1 3
1 4
2 2
2 4
3 5
And I'm looking for a query where I can give it a list of ingredients_master_id such as 2,4 and it returns all of the drinks_id's that have exactly 2,4.
So in this case if I gave it ingredients_master_id 2,4,5 it would return drinks_id 2 and 3. And if I gave it 5 it would return drinks_id 3.
This is what I have so far but it's currently not displaying the correct info.
SELECT DISTINCT drinks.id
FROM drinks
WHERE drinks.id NOT IN
(
SELECT drinks.id
FROM ingredients
JOIN drinks ON ingredients.drinks_id = drinks.id
WHERE ingredients.ingredients_master_id NOT IN
(
2,3,4,5,6
)
);
You probably achieve the desired result using not exists as follows:
Select t.*
From your_table t
Where t.ingredients_master_id in (2,4,5)
And not exists
(Select 1 from your_table tt
Where tt.drinks_id = t.drinks_id
And tt.ingredients_master_id not in (2,4,5))
And I'm looking for a query where I can give it a list of ingredients_master_id such as 2,4 and it returns all of the drinks_id's that have exactly 2,4.
You can use group by and having:
select drinks_id
from t
group by drinks_id
having sum( ingredients_master_id in (2, 4) ) = 2;
The "= 2" is the size of the list, so you need to adjust that for different lists.
You can use as below:
select drink_id
from (
select drink_id,listagg(ingredients_master_id,',') within group( order by ingredients_master_id) val from <Table> group by drink_id)
where case
when instr('**2,4,5**',val)> 0
Then 'Y'
else 'N'
end = 'Y';

Count first occurence with column value ordered by another column

I have an assigns table with the following columns:
id - int
id_lead - int
id_source - int
date_assigned - int (this represents a unix timestamp)
Now, lets say I have the following data in this table:
id id_lead id_source date_assigned
1 20 5 1462544612
2 20 6 1462544624
3 22 6 1462544615
4 22 5 1462544626
5 22 7 1462544632
6 25 6 1462544614
7 25 8 1462544621
Now, lets say I want to get a count of the rows whose id_source is 6, and is the first entry for each lead (sorted by date_assigned asc).
So in this case, the count would = 2, because there are 2 leads (id_lead 22 and 25) whose first id_source is 6.
How would I write this query so that it is fast and would work fine as a subquery select? I was thinking something like this which doesn't work:
select count(*) from `assigns` where `id_source`=6 order by `date_assigned` asc limit 1
I have no idea how to write this query in an optimal way. Any help would be appreciated.
Pseudocode:
select rows
with a.id_source = 6
but only if
there do not exist any row
with same id_lead
and smaller date_assigned
Translate it to SQL
select * -- select rows
from assigns a
where a.id_source = 6 -- with a.id_source = 6
and not exists ( -- but only if there do not exist any row
select 1
from assigns a1
where a1.id_lead = a.id_lead -- with same id_lead
and a1.date_assigned < a.date_assigned -- and smaller date_assigned
)
Now replace select * with select count(*) and you'll get your result.
http://sqlfiddle.com/#!9/3dc0f5/7
Update:
The NOT-EXIST query can be rewritten to an excluding LEFT JOIN query:
select count(*)
from assigns a
left join assigns a1
on a1.id_lead = a.id_lead
and a1.date_assigned < a.date_assigned
where a.id_source = 6
and a1.id_lead is null
If you want to get the count for all values of id_source, the folowing query might be the fastest:
select a.id_source, count(1)
from (
select a1.id_lead, min(a1.date_assigned) date_assigned
from assigns a1
group by a1.id_lead
) a1
join assigns a
on a.id_lead = a1.id_lead
and a.date_assigned = a1.date_assigned
group by a.id_source
You still can replace group by a.id_source with where a.id_source = 6.
The queries need indexes on assigns(id_source) and assigns(id_lead, date_assigned).
Simple query for that would be
check here http://sqlfiddle.com/#!9/8666e0/7
select count(*) from
(select * from assigns group by id_lead )t
where t.id_source=6

Getting Follower and FollwedBy Users from Table in one list

I have a Table that tracks followers
FollowerUserId, FollowingUserId
1 2
2 1
3 1
4 1
1 5
I want to get all user that given Id follows and is followed by or Both.
for example for UserId 1,I want result to be: (FG: Following, FD: Followed, B: Both ways)
2,B
5,FG
3,FD
4,FD
i can easily get FG and FD by doing union
Select FollowerUserId, 'FD' From Table Where FollowingUserId =1
Union
Select FollowingUserId, 'FG' From Table Where FollowerUserId =1;
with above i get user 2 as
2,FG
2,FD
from above but I really need 2,B without UserId 2 duplicated.
How can this be done efficiently?
You can use aggregation on your basic query:
SELECT UserId,
(CASE WHEN COUNT(DISTINCT which) = 1 THEN MIN(which)
ELSE 'B'
END)
FROM (Select FollowerUserId as UserId, 'FD' as which From Table Where FollowingUserId = 1
Union ALL
Select FollowingUserId, 'FG' From Table Where FollowerUserId = 1
) f
GROUP BY UserId;

Query to solve in mysql

My table have data like this
id from
1 1|Chinmoy Panda|chinmoy|mfsi_chinmoyp
1 532|Narendra Mallik|narendram
1 595|Bhagirathi Panda|bhagirathi
2 1|Chinmoy Panda|chinmoy|mfsi_chinmoyp
2 532|Narendra Mallik|narendram
2 595|Bhagirathi Panda|bhagirathi
2 13|Hemendra Singh|hemendras
3 1|Chinmoy Panda|chinmoy|mfsi_chinmoyp
3 595|Bhagirathi Panda|bhagirathi
3 13|Hemendra Singh|hemendras
4 1|Chinmoy Panda|chinmoy|mfsi_chinmoyp
4 595|Bhagirathi Panda|bhagirathi
5 595|Bhagirathi Panda|bhagirathi
i am trying to this
Ignore the 1st row of every id
Count w.r.t. from
Ignore if the id has one row.
Means
Count from
4 595|Bhagirathi Panda|bhagirathi
2 532|Narendra Mallik|narendram
2 13|Hemendra Singh|hemendras
In 1,2,3,4 id 1st row contains chinmay panda.So i ignore that one
Bhagirathi Panda occured 5 times but id 5 having only one row so count is 4.
similarly for others
i tried but unable to find the result
please help me to write the query
(i didn't get what should the title so i write this one. )
thanks in advance.
You want a query something like this:
select count(*), from
from t
where left(from, 2) <> '1|' and
t.id in (select id from t group by id having COUNT(*) > 1)
group by from
However, because the column names are poorly named (using SQL reserved words), you need to properly quote them.
Also, I'm assuming that by "first" you mean the ones that start with '1|'.
this query will do
SELECT
COUNT(*) `count`,
`from`
FROM (
SELECT
`from`,
IF( COALESCE( #id, 0 ) = (#id := id) , #curRow := #curRow + 1, #curRow := 1 ) curRow
FROM
Table1 ) tmp
WHERE curRow > 1
GROUP BY `from`
ORDER BY `count` desc
SQL Fiddle DEMO

counting overlapping bitwise columns in mysql

I have a table in which there is a bitwise column representing a list of statuses that can be attached to an entry. Each entry can have multiple statuses selected (hence the use of the bitwise logic).
What I'd like to do is pull a query that will tell me how many entires there are for each status (i.e. how many times each bit is turned on). The difficulty I have is that there is of course overlap so a GROUP BY or a DISTINCT is not going to cut it (as far as I can see).
As an example let's just have two values, 1 and 2. and the following data
Id | Status
1 | 1
2 | 1
3 | 2
4 | 3
Now, I want to count how many entries there are for each bit so I'd like something that counts that 3 value into both the 1 and 2 totals, outputting something like this:
Bit | Count
1 | 3
2 | 2
The closest I can get so far seems to be pulling out the distinct values and then adding those with multiple entries into their corresponding counts using PHP. Obviously, I'd like to do something a bit more elegant.
Any ideas?
Expand the bits table as required
select `bit`, count(*) `count`
from bitt s
inner join (select 1 `bit` union all
select 2 union all
select 3 union all
select 4 union all
select 5) bits on s.status & Pow(2,bits.`bit`-1)
group by bits.`bit`
You could do:
SUM(IF(`Status`&1,1,0)) as `count1`,
SUM(IF(`Status`&2,1,0)) as `count2`,
SUM(IF(`Status`&4,1,0)) as `count4`
If you want to optimize it, you can still GROUP BY Status, but then you would need (a little) post-processing to sum the 8 rows you would get for a 3-bit situation.
One more variant -
SELECT 0, COUNT(IF(status >> 0 & 1 = 1, 1, NULL)) FROM table1
UNION
SELECT 1, COUNT(IF(status >> 1 & 1 = 1, 1, NULL)) FROM table1
UNION
SELECT 2, COUNT(IF(status >> 2 & 1 = 1, 1, NULL)) FROM table1
...