How to select rows based on condition - sql

The following is the code snippet.
Just design purpose I have added.
Here The user will be assigned multiple group.
So I want to select the person details alone.
Here Person id 103 have two different persmission for the same Product.
But the higher permission only be selected for the person.
But if he is not assinged to multiple group, the default permission should be selected.
Sample data
ProdId PersonId GroupId Permission
10103 78 55 15
10103 99 33 15
10103 100 33 0
10103 103 33 15
10103 103 40 0
10103 112 33 15
Result data should be
ProdId PersonId Permission
10103 78 15
10103 99 15
10103 100 0
10103 103 15
10103 112 15

You should use ROW_NUMBER() :
SELECT * FROM (
SELECT t.*,
ROW_NUMBER() OVER(PARTITION BY t.prodid,t.personID ORDER BY t.permission DESC) as rnk
FROM YourTable t) s
WHERE s.rnk = 1
I assumed you want the highest number on permission by your example? If not, change the ORDER BY clause to what you want.
Right now it will select all columns, specify the ones you want.

If you are using Oracle, try the below query..
select * from (
select ProdID, PersonID, Permission, row_number() over (partition by PersonID order by Permission Desc) as column1 from table1)
where column1 = 1;

Related

Get sum qty over specific range

I have the below table
substring(area,6,3)
qty
101
10
103
15
102
11
104
30
105
25
107
17
108
23
106
48
And I am looking to get a result as below without repeating the IIF ( as it's a cumulative of 4 sequences) in the area:
new_area(substring(area,6,3)
sum_qty
101-104
66
105-108
117
I don't know how to create the new area column to be able to get the sum qty
Looking forward to your help.
Please also add an explanation so I will understand how the query is running.
I think this is what you are looking for.
We just use the window function row_number() to create the Grp
NOTE: If you have repeating values in AREA use dense_rank() instead of row_number()
Example
Select new_area = concat(min(area),'-',max(area))
,qty = sum(qty)
From (
Select area=substring(area,6,3)
,qty
,Grp = (row_number() over (order by substring(area,6,3))-1) / 4
From YourTable
) A
Group By Grp
Results
new_area qty
101-104 66
105-108 113 -- get different results
If you were to run the subquery, you would see the following.
Then it becomes a small matter to aggregate the data grouped by the created column GRP

How to find number of distinct phones per customer and put the customers(counts) in different buckets as per the counts?

Below is the table where I have customer_id and different phones they have.
customer_id phone_number
101 123456789
102 234567891
103 345678912
102 456789123
101 567891234
104 678912345
105 789123456
106 891234567
106 912345678
106 456457234
101 655435664
107 453426782
Now, I want to find customer_id and distinct phone number count.
So I used this query:
select distinct customer_id ,count(distinct phone_number)
from customer_phone;
customer_id no of phones
101 3
102 2
103 1
104 1
105 1
106 3
107 1
And, from the above table my final goal is to achieve the below output which takes the counts and puts in different buckets and then count number of consumers that fall in those buckets.
Buckets no of consumers
3 2
2 1
1 4
There are close to 200 million records. Can you please explain an efficient way to work on this?
You can use width_bucket for that:
select bucket, count(*)
from (
select width_bucket(count(distinct phone_number), 1, 10, 10) as bucket
from customer_phone
group by customer_id
) t
group by bucket;
width_bucket(..., 1, 10, 10) creates ten buckets for the values 1 through 10.
Online Example: http://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=1e6d55305570499f363837aba21bdc7e
Use two aggregations:
select cnt, count(*), min(customer_id), max(customer_id)
from (select customer_id, count(distinct phone_number) as cnt
from customer_phone
group by customer_id
) c
group by cnt
order by cnt;

How to select 6 top records of each individual records at the database when selecting from all rows

Assume that i have the following table
CREATE TABLE #tblUsersPokemons (
RecordId int NOT NULL,
PokemonId int NOT NULL,
PokemonExp int NOT NULL,
PokemonLevel int NOT NULL,
UserId int NOT NULL
)
Now the below query works awesome as expected
select
SUM(cast(PokemonExp as bigint)) as TotalExp,
MAX(PokemonLevel) as MaxPokeLevel,
Count(PokemonId) as TotalPoke,
UserId
from #tblUsersPokemons
group by UserId
Here example result of such query
ToplamExp MaxPokeLevel TotalPoke UserId
----------- --------------- ----------- --------
29372294 101 4 1
1134696 98 1 2
1400 98 1 101
24534365 98 4 102
1400 98 1 1102
1400 98 1 1103
1400 98 1 2102
1400 98 1 2103
789220 98 7 2105
1468 98 1 3104
Now here my question comes
I want to limit counted PokemonIds. What i mean is i want to select maximum 6 of each same PokemonId records. And from these records top 6 ordered desc by PokemonExp should be counted in.
For example a user has the below records
From this table the query should take record id : 1,2,3,4,5,6,9 and not take 7,8 since top 6 records for PokemonId 1 taken
If I understand correctly, you want the aggregations on the top 6 rows for each user. You can do this easily using row_number():
select SUM(cast(PokemonExp as bigint)) as ToplamExp,
MAX(PokemonLevel) as MaxPokeLevel,
Count(PokemonId) as TotalPoke,UserId
from (select p.*,
row_number() over (partition by userid order by pokemanexp desc) as seqnum
from tblUsersPokemons p
) p
where seqnum <= 6
group by UserId;
EDIT:
I think you want to include PokemonId in the partition by clause:
select SUM(cast(PokemonExp as bigint)) as ToplamExp,
MAX(PokemonLevel) as MaxPokeLevel,
Count(PokemonId) as TotalPoke,UserId
from (select p.*,
row_number() over (partition by userid, PokemonId
order by pokemanexp desc) as seqnum
from tblUsersPokemons p
) p
where seqnum <= 6
group by UserId;

SQL Access -- Keep record only with most recent timestamp

I have a table that appears as follows:
Time Name Cust_ID Num_Calls Num_Orders
12.00 ABC 100 20 10
12.25 PQR 102 23 12
12.30 ABC 100 26 15
01.00 ABC 100 26 18
02.00 PQR 102 23 14
04.00 PQR 102 25 20
How do I delete the earlier records for each "Name & Cust_ID" and keep the most recent one. The other fields in the record may change as I run them through my Access Database, but Name and ID remains the same.
My output at the End of the Day should be:
Time Name Cust_ID Num_Calls Num_Orders
01.00 ABC 100 26 18
04.00 PQR 102 25 20
I think if your cust_id is unique, you should make it a primary key in the table.
Then whenever you have a new entry, first check and see if the current cust_id already exists.
If yes, update that entry in the table.
Else do an insert.
Try this...
This should give you your most recent records based on max(time), you could delete the complement of this set.
SELECT * FROM YOUR_TABLE A
INNER JOIN
( SELECT MAX(time) MAX_time
, NAME , CUST_ID
FROM YOUR_TABLE
GROUP BY
NAME , CUST_ID )B
ON A.NAME=B.Name
and A.CUST_ID=B.CUst_ID
and A.time =B.max_time
So you would delete the following records
DELETE FROM YOUR_TABLE
WHERE EXISTS
(SELECT * FROM YOUR_TABLE B
WHERE TIME <>( SELECT MAX(time) FROM YOUR_TABLE C WHERE B.NAME=C.Name
and C.CUST_ID=B.CUst_ID )
AND A.NAME=B.Name
and A.CUST_ID=B.CUst_ID)

Sql get latest records of the month for each name

This question is probably answered before but i cant find how to get the latest records of the months.
The problem is that I have a table with sometimes 2 row for the same month. I cant use the aggregate function(I guess) cause in the 2 rows, i have different data where i need to get the latest.
Example:
name Date nuA nuB nuC nuD
test1 05/06/2013 356 654 3957 7033
test1 05/26/2013 113 237 399 853
test3 06/06/2013 145 247 68 218
test4 06/22/2013 37 37 6 25
test4 06/27/2013 50 76 20 84
test4 05/15/2013 34 43 34 54
I need to get a result like:
test1 05/26/2013 113 237 399 853
test3 06/06/2013 145 247 68 218
test4 05/15/2013 34 43 34 54
test4 06/27/2013 50 76 20 84
** in my example the data is in order but in my real table the data is not in order.
For now i have something like:
SELECT Name, max(DATE) , nuA,nuB,nuC,nuD
FROM tableA INNER JOIN
Group By Name, nuA,nuB,nuC,nuD
But it didn't work as i want.
Thanks in advance
Edit1:
It seems that i wasn't clear with my question...
So i add some data in my example to show you how i need to do it.
Thanks guys
Use SQL Server ranking functions.
select name, Date, nuA, nuB, nuC, nuD from
(Select *, row_number() over (partition by name, datepart(year, Date),
datepart(month, Date) order by Date desc) as ranker from Table
) Z
where ranker = 1
Try this
SELECT t1.* FROM Table1 t1
INNER JOIN
(
SELECT [name],MAX([date]) as [date] FROM Table1
GROUP BY [name],YEAR([date]),MONTH([date])
) t2
ON t1.[date]=t2.[date] and t1.[name]=t2.[name]
ORDER BY t1.[name]
Can you not just do an order
select * from tablename where Date = (select max(Date) from tablename)
followed by only pulling the first 3?