Comparing values within a column using sql - mysql

I have a table with three columns Member, id and DOB. I want to assign a id to each unique member. If there is more than one id tagged for a member then I have to assign id with more recurrence. If a tie occurs then I have to assign id with most recent DOB.
4000 8569 11/11/1993
4111 9653 12/11/1993
4000 8569 12/12/1993
5000 5632 01/01/1993
4000 6932 31/12/1993
4111 6987 06/11/1993
5001 4356 01/01/1993
In the above, member's 5000 and 5001 is tagged to single id.. So I should get the same id for that member.. Whereas for member 4000 I am having 3 id's- 2 same ids (8569) and one different id (6987). Here I should have 8569 tagged to this 4000 member. For 4111 member, I am having two different ids (9653 and 6987). So I will see recent DOB for that member. So for 4111 member I will have 9653 tagged to it.
The output should be like this:
4000 8569
4111 9653
5000 5632
5001 4356
I have tried many. But I couldn't get the exact answer. Please help me to solve this. Thanks in advance.

You can do this with window functions in t-sql:
create table #t (
Member int,
id int,
DOB date
);
insert into #t
values (4000, 8569, '1993-11-11'),
(4111, 9653, '1993-11-12'),
(4000, 8569, '1993-12-12'),
(5000, 5632, '1993-01-01'),
(4000, 6932, '1993-12-31'),
(4111, 6987, '1993-11-06'),
(5001, 4356, '1993-01-01');
with cte as
(
select *, count(id) over (partition by member, id) cnt from #t
),
cte2 as
(
select *, row_number() over (partition by member order by cnt desc, dob desc) rn from cte
)
select member, id from cte2 where rn = 1;
drop table #t;

Related

Mysql select query until reach the condition

Lets say I have list of users in my user table like below. I need to find the count of users from my table until the userid is equal to 100.
So here the answer is (3). But how can i find this is MySQL query. Any idea?
userid name
---------------
10 aaa
30 bbb
100 ccc
60 ddd
This is one of the work around to achieve your expectation.
SET #row_number:=0;
SELECT A.row_number FROM (
SELECT Userid, name, #row_number:=#row_number+1 AS row_number
FROM UserDetail
) AS A
WHERE A.Userid = 100;
Working DEMO
In case if the UserId is the not the unique id and it can repeat, you may add the ORDER BY with LIMIT 1
SET #row_number:=0;
SELECT A.row_number FROM (
SELECT Userid, name, #row_number:=#row_number+1 AS row_number
FROM UserDetail
) AS A
WHERE A.Userid = 100
ORDER BY A.row_number
LIMIT 1;
Working DEMO
Sample execution with given data:
--DROP TABLE UserDetail;
CREATE TABLE UserDetail (Userid INT, name VARCHAR (50));
INSERT INTO UserDetail (Userid, name) VALUES
(10 , 'Aaa'),
(30 , 'Bbb'),
(100, 'Ccc'),
(60 , 'ddd');
SET #row_number:=0;
SELECT A.row_number FROM (
SELECT Userid, name, #row_number:=#row_number+1 AS row_number
FROM UserDetail
) AS A
WHERE Userid = 100;
This is difficult to do in MySql as the 'first' instance of a number can be difficult to pin down.
One way to resolve this would be to create row numbers, then choose the minimum row number with Userid = 100
select min(row_number) from
(
SELECT #rownum:=#rownum + 1 as row_number,
p.*
FROM p,
(SELECT #rownum := 0) r
) g
where userid = 100
Here is a functional example

MySql Sum and Count for simple table

Could you help me with simple table SUM and COUNT calculating?
I've simple table 'test'
id name value
1 a 4
2 a 5
3 b 3
4 b 7
5 b 1
I need calculate SUM and Count for "a" and "b". I try this sql request:
SELECT name, SUM( value ) AS val, COUNT( * ) AS count FROM `test`
result:
name val count
a 20 5
But should be
name val count
a 9 2
b 11 3
Could you help me with correct sql request?
Add GROUP BY. That will cause the query to return a count and sum per group you defined (in this case, per name).
Without GROUP BY you just get the totals and any of the names (in your case 'a', but if could just as well have been 'b').
SELECT name, SUM( value ) AS val, COUNT( * ) AS count
FROM `test`
GROUP BY name
You need group by
select
name,
sum(value) as value,
count(*) as `count`
from test group by name ;

Ho to assign Previous value in column for each record

I have one table scenario in which data looks like this .
Request Id Field Id Current Key
1213 11 1001
1213 12 1002
1213 12 103
1214 13 799
1214 13 899
1214 13 7
In this when loop starts for first Request ID then it should check all the field ID for that particular request ID. then data should be look like this .
Request Id Field Id Previous Key Current Key
1213 11 null 1001
1213 12 null 1002
1213 12 1002 103
1214 13 null 799
1214 13 799 899
1214 13 899 7
When very first record for Field id for particular request id come then for it should be take null values in Previous key column and the current key will remain the same.
When the second record will come for same field ID its should take previous value of first record in Previous key column and when third record come it should take previous value of second record in Previous column and so on .
When the new field ID came the same thing should be repeated again.
Please let me know if you need any more info.Much needed your help.
You can check this.
Declare #t table (Request_Id int, Field_Id int, Current_Key int)
insert into #t values (1213, 11, 1001),(1213, 12, 1002), (1213, 12, 103) , (1214, 13, 799), (1214, 13, 899), (1214, 13, 7)
;with cte
as (
select 0 rowno,0 Request_Id, 0 Field_Id, 0 Current_Key
union
select ROW_NUMBER() over(order by request_id) rowno, * from #t
)
select
t1.Request_Id , t1.Field_Id ,
case when t1.Request_Id = t2.Request_Id and t1.Field_Id = t2.Field_Id
then t2.Current_Key
else null
end previous_key
, t1.Current_Key
from cte t1, cte t2
where t1.rowno = t2.rowno + 1
Refer link when you want to compare row value
When the second record will come for same field ID...
Tables don't work this way: there is no way to tell that 1213,12,1002 is the "previous" record of 1213,12,103 as you assume in your example.
Do you have any data you can use to sort your records properly? Request id isn't enough because, even if you guarantee that it increments monotonically for each operation, each operation can include multiple values for the same item id which need to be sorted relative to each other.
IN SQL 2008
You do not have the benefit of the lead and lag functions. Instead you must do a query for the new column. Make sure you query both tables in the same order, and add a row_num column. Then select the greatest row_num that is not equal to the current row_num and has the same request_id and field_id.
select a.request_id,
a.field_id,
(select x.current_key
from (select * from (select t.*, RowNumber() as row_num from your_table t) order by row_num desc) x
where x.request_id = a.request_id
and x.field_id = a.field_id
and x.row_num < a.row_num
and RowNumber()= 1
) as previous_key,
a.current_key
from (select t.*, RowNumber()as row_num from your_table t) a
IN SQL 2012+
You can use the LAG or LEAD functions with the OVER clause to get the previous or next nth row value:
select
Request_Id,
Field_Id,
lag(Current_Key,1) over (partition by Request_ID, Field_ID) as Previous_Key
,Current_Key
from your table
You should probably look at how you order your results too. If you have multiple results lag will only grab the next row in the default order of the table. If you had another column to order by such as a date time you could do the following:
lag(Current_Key,1) over (partition by Request_ID, Field_ID order by timestampColumn)
try this,
declare #tb table (RequestId int,FieldId int, CurrentKey int)
insert into #tb (RequestId,FieldId,CurrentKey) values
(1213,11,1001),
(1213,12,1002),
(1213,12,103),
(1214,13,799),
(1214,13,899),
(1214,13, 7)
select RequestId,t.FieldId,
case when t.FieldId=t1.FieldId then t1.CurrentKey end as PreviousKey,t.CurrentKey from
(select *, ROW_NUMBER() over (order by RequestId,FieldId) as rno
from #tb) t left join
(select FieldId,CurrentKey,
ROW_NUMBER() over (order by RequestId,FieldId) as rno from #tb) t1 on t.rno=t1.rno+1

SQL Server: get median value

How can i get the median value of each one of grouped values of a collumn from a select statement. I guess i use Row number but not sure how to go about it.
Note: if even number just take either middle no.
name size
joe 10
joe 11
joe 19
joe 20
joe 47
sally 3
sally 8
sally 57
john 1
john 3
I want to get Joe 19, Sally 8, John 3
Set up testing data:
CREATE TABLE #Foo (Name varchar(10), value int)
INSERT #Foo values
('joe', 10)
,('joe', 11)
,('joe', 19)
,('joe', 20)
,('joe', 47)
,('sally', 3)
,('sally', 8)
,('sally', 57)
,('john', 1)
,('john', 3)
First pass, get proper ordering:
SELECT Name, Value, row_number() over (partition by name order by value) ranking
from #Foo
Second pass, identify median item (If even number of items, the "first" item found is always returned)
;WITH cteRankings (Name, Value, Ranking)
as (select Name, Value, row_number() over (partition by name order by value) ranking
from #Foo)
SELECT Name, avg(Ranking) MedianItem
from cteRankings
group by Name
Final pass, get the details for the median item:
;WITH cteRankings (Name, Value, Ranking)
as (select Name, Value, row_number() over (partition by name order by value) Ranking
from #Foo)
SELECT cte.Name, cte.Value
from cteRankings cte
inner join (-- Median items
select Name, avg(Ranking) MedianItem
from cteRankings
group by Name) xx
on xx.Name = cte.Name
and xx.MedianItem = cte.Ranking
order by cte.Name
Done as a cte (common table expression), because a subquery was called for and needed to be referenced twice.

How to distribute accounts on users equally based on a time zone in mysql?

I have 1000 account. each account has account_name, account_id, time_zone_id
I want to generate activities for every account to 3 users.
So I will need to generate 333 activities for used #10 and 333 for user #11 and 334 for user #12. But I need to make sure that the time zone is distributed equally. so if I have 200 account in a time zone 18 and 400 account in time zone 10 and 200 in time zone 7 and 200 in time zone 39 then I want to make sure I distribute those new activities for the users equally
I have tried something like this as a select to get the count and see if I am going the correct direction
SELECT count(ac.account_id) AS total, ac.time_zone_id,
(SELECT user_id FROM users where team_id = 4 ORDER BY RAND() LIMIT 1 ) AS user_id
FROM accounts AS ac
GROUP BY ac.time_zone_id
this created the activities but it is not equal distribution.
The following would return a user_no ( 10-12 ) for each account.
It sorts by time_zone_id and then uses the mod function to pick each of the three users in turn (user 10 for the first result, 11 for second, 12 for third, 10 for fourth and so on).
set #r = 0 ;
select
#r:=#r+1 row_no,
account_id,
account_name,
mod(#r,3)+10 user_no
from
account
order by
time_zone_id
Revision
you can get users in a similar way
set #ur = 0;
select
#ur:=#ur+1 user_row_no,
user_id
from users
where team_id = 4
Revised again
It would be something like this
Make some sample data
create table users( user_id int, team_id int) ;
insert into users select 2,4
union select 3,4
union select 1,2
union select 7,4
union select 6,4;
create table account ( account_id int,
account_name varchar(20),
time_zone_id varchar(3),
assigned_to int
);
insert into account(account_id ,account_name,time_zone_id)
select 1,'Janice','pst'
union select 2,'Jonny','gmt'
union select 3,'Jane','gmt'
union select 4,'Janet','pst'
union select 5,'James','gmt';
Make a table to pop the users in that we are interested in
(could/should be a temp_table)
create table temp_user( id int AUTO_INCREMENT primary key,
user_id int
);
insert into temp_user( user_id )
select user_id
from users
where team_id = 4;
The update
set #r=0;
update account join
(
select
#r:=#r+1 row_no,
account_id,
account_name,
assigned_to
from
account
order by
time_zone_id
) x
on x.account_id = account.account_id
join
temp_user
on
temp_user.id=(1+ mod(row_no,(select count(*) from temp_user)))
set account.assigned_to = temp_user.user_id
http://sqlfiddle.com/#!2/164733/10