Sql to select Max event on two grouped by one column - sql

I have the following table :
+----------+------+
| country | event |
+----------+-----------+
| usa | running |
| usa | running |
| usa | running |
| canada | running |
| Canada | running |
| usa | javline |
| canada | javline |
| canada | javline |
| canada | javline |
+----------+-----------+
I want to get the following out by sql query:
USA | Running | 3
Canada | Javline | 3
i tried using the following query on MS sql server :
select country, case when c > 1 then null else event end event
from (select country, [ModelName], recs, count(*) over (partition by event, recs ) c,
row_number() over (partition by country order by recs desc) rn
from (select country, event, count(*) recs
from table
group by country, event) )
where rn = 1
order by 1
But I get an error :
Msg 102, Level 15, State 1, Line 12
Incorrect syntax near ')'.
Any pointers to correct solution is appreciated. Thanks.

You need to put an alias on your subquery:
select
country,
case when c > 1 then null else event end event
from (
select -- No event here
country,
[ModelName],
recs,
count(*) over (partition by event, recs ) c,
row_number() over (partition by country order by recs desc) rn
from (
select country, event, count(*) recs -- No ModelName here
from [table]
group by country, event
) x -- You need to put an alias here
)t -- and here
where rn = 1
order by 1
Note that the above query will still produce errors:
Invalid column name 'ModelName'.
Invalid column name 'event'.
This is because ModelName is not included in your innermost subquery and event is not included in the outermost subquery.
Based on your sample data, you can use this query to achieve the desired result:
;WITH Cte AS(
SELECT Country, Event, COUNT(*) AS CC
FROM [Table]
GROUP BY Country, Event
)
,CteRowNumber AS(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY Country ORDER BY CC DESC)
FROM Cte
)
SELECT Country, Event, CC
FROM CteRowNumber
WHERE RN = 1

You could do it using window function inside a cte:
-- this counts a number per each country and event
with q as(
select country,event,
row_number() over(partition by country,event order by country) r
from your_table t
)
--this takes only the maximum of them
select *
from q
where r=(select max(r)
from q q2
where q2.country=q.country)
Result:
| country | event | r |
|---------|---------|---|
| canada | javline | 3 |
| usa | running | 3 |

Related

Row Number by Certain Column in SQL

I have a table that contains customer transactions. It looks like this:
Tha data is sorted by Total Transaction. I want to create a column that contains number by City. For Example, the first row shows City is London so the values is 1, second row becaus it's from London too, the value is also 1. When the Next Row is not London, the value is 2. So it looks like this:
Is there a way to create that row number in SQL Server?
You can try using dense_rank()
select *,dense_rank() over(order by city) as cityNumber
from tablename
order by total_transaction desc
I believe the question is valid and as per my understanding on the requirement , you need a two level of sub query to get to the final result,
Here I have used max as the data first has to be sorted by Total Transaction and then we can use dense_rank to give a row number using the max value and city.
select t.city as "City"
,dense_rank() over (order by max_total_per_city desc,city) as "City Number"
,t.customer as "Customer"
,t.total_transaction as "Total Transaction"
from
(
select *
,max(total_transaction) over (partition by city) as max_total_per_city
from tableName t
) t
order by total_transaction desc
You can get the CityNumbers with ROW_NUMBER() window function:
select City, row_number() over (order by max(TotalTransaction) desc) CityNumber
from tablename
group by City
so you can join the above query to the table:
select t.City, c.CityNumber, t.Customer, t.Totaltransaction
from tablename t inner join (
select City, row_number() over (order by max(TotalTransaction) desc) CityNumber
from tablename
group by City
) c on c.City = t.City
order by t.TotalTransaction desc
Or with DENSE_RANK() window function:
select t.City,
dense_rank() over (order by (select max(TotalTransaction) from tablename where City = t.City) desc) as cityNumber,
t.Customer,
t.TotalTransaction
from tablename t
order by t.TotalTransaction desc
See the demo.
Results:
> City | CityNumber | Customer | Totaltransaction
> :--------- | ---------: | :------- | ---------------:
> London | 1 | Michael | 250
> London | 1 | Edward | 180
> Paris | 2 | Michael | 160
> Madrid | 3 | Luis | 153
> London | 1 | Serena | 146
> Madrid | 3 | Lionel | 133
> Manchester | 4 | Frank | 96

MAX Grouping by 2 columns

I'm stumped as in how to do this.
I have 3 columns the first is a parent company, second is the child and the third is it's revenue. I want to find out which child per parent has the most revenue and what that revenue is.
So like the below
Vodafone. Argentina. 5b
Vodafone. Spain. 4b
Vodafone. England. 10b
So the answer would be
Vodafone. England 10b
Apologies for the formatting, on my phone.
You can use row_number(). Here is the demo.
select
company,
child,
revenue
from
(
select
*,
row_number() over (partition by company order by cast(revenue as int) desc) as rn
from yourTable
) subq
where rn = 1
output:
| company | child | revenue |
| -------- | ------- | ------- |
| Vodafone | England | 10 |
You can use dense_rank() if more than one company have same revenue.
You can try the below one -
select * from tablename
where cast(revenue as int) = (select max(cast(revenue as int)) from tablename)

Get First Row of SubQuery

I have a table with clients and I need to show the first country of each client like a default country.
Table Clients
ID_Client | Name_Client
1 | Mike
2 | Jon
3 | Ben
Table Countries
ID_Country | ID_Client | Name_Country
1 | 1 | France
2 | 1 | USA
3 | 1 | England
4 | 2 | Portugal
5 | 2 | Spain
6 | 3 | Germany
I only want the first row of each country.
Example:
Mike - France
Jon - Portugal
Ben - Germany
I tried this but only retry 1 row:
SELECT Name_Client, Name_Country
FROM Clients
WHERE ID_Client =
(SELECT TOP 1 ID_Client
From Countries
order by ID_Country)
Result:
Mike | France
Your sub-query isn't correlated, try to use APPLY :
SELECT c.Name_Client, cn.Name_Country
FROM Clients C OUTER APPLY
(SELECT TOP (1) cn.Name_Country
From Countries CN
WHERE cn.ID_Client = c.ID_Client
ORDER BY cn.ID_Country
) cn;
You can use Outer APPLY or CROSS APPLY as per Below example,
SELECT C.Name_Client + ' - ' + V.Name_Country
FROM Clients C
OUTER APPLY(
SELECT TOP 1 * FROM Countries CO WHERE CO.ID_Client = C.ID_Client
ORDER BY ID_Country
) V
SQL Fiddle
MS SQL Server 2017 Schema Setup:
CREATE TABLE CLIENTS (ID_Client int,Name_Client varchar(255))
CREATE TABLE COUNTRIES(ID_Country int,ID_Client int,Name_Country varchar(255))
INSERT INTO CLIENTS(ID_Client,Name_Client)VALUES(1,'Mike'),(2,'Jon'),(3,'Ben')
INSERT INTO COUNTRIES(ID_Country,ID_Client,Name_Country)VALUES(1,1,'France'),
(2,1,'USA'),(3,1,'England'),
(4,2,'Portugal'),(5,2,'Spain'),
(6,3,'Germany')
Query 1:
with CTE as
( select c.Name_Client, ct.Name_Country,
row_number() over(partition by c.ID_Client order by ct.ID_Country) as rn
FROM CLIENTS c
left join COUNTRIES ct on c.ID_Client=ct.ID_Client
)
select CTE.Name_Client,CTE.Name_Country from CTE where rn=1
Results:
| Name_Client | Name_Country |
|-------------|--------------|
| Mike | France |
| Jon | Portugal |
| Ben | Germany |
Rather than having a nested query like this try this instead.
SELECT clients.Name_Client, countries.Name_Country
FROM Clients clients
LEFT JOIN Countries countries on countries.ID_Client = clients.ID_Client
By performing the join you are matching the record and not having a subquery go off and get a bucket load of bad data.
use row_number()
with cte as
( select c.Name_Client, cn.Name_Country,
row_number() over(partition by c.ID_Client order by ID_Country) rn clients c join country cn on c.client_id=cn.client_id
) select * form cte where rn=1
You can use common table expression and filter on the row number partitioned by the id_client. Like this the row_number is incremented until a new id_client is found.
WITH cte_countries AS(
SELECT ROW_NUMBER() OVER (PARTITION BY ID_Client ORDER BY ID_Client) AS Row#,
Countries.*
FROM Countries)
SELECT * FROM Clients cli
JOIN cte_countries coun ON cli.ID_Client = coun.ID_Client
WHERE coun.Row# = 1
You can try this
SELECT * FROM (
SELECT Name_Client, Name_Country ,
RwNumbr = ROW_NUMBER() OVER(PARTITION by c.ID_Client order by cl.ID_Country)
from CLIENTS c
JOIN COUNTRIES cl
ON cl.ID_Client = c.ID_Client
) as f
WHERE f.RwNumbr = 1

Select all data with no duplicate data

I have some data in database:
Name | Country | Status
Mary | USA | Pending
Jane| Japan | Pending
Jane | Korea | Pending
Adrian | China | Pending
Peter | Singapore | Pending
Jack | Malaysia | Pending
Adrian | China | Updated
Jane | Japan | Updated
May I know how to use the SELECT query to select all the data with no duplicate data? (If the duplicates data exist, select only the Status with Updated)
Try:
SELECT Name, Country, MAX(Status) as Status FROM (
SELECT TOP 100 PERCENT *
FROM NameCountry
ORDER BY Name ASC, Country ASC, Status DESC
) G
GROUP BY G.Name, G.Country
ORDER BY G.Name, G.Country
Check my Demo
From your comment, you seem to mean only data where the first two columns are duplicated. The easiest way, I think, is to use row_number(), which is available in most databases:
select name, country, status
from (select t.*,
row_number() over (partition by name, country
order by (case when status = 'Pending' then 0 else 1 end)
) as seqnum
from t
) t
where seqnum = 1

Select from results of query?

I have a query like this:
SELECT Weighings.Member, MIN(Sessions.DateTime) AS FirstDate, MAX(Sessions.DateTime) AS LastDate
FROM Weighings AS Weighings INNER JOIN
Sessions ON Sessions.SessionGUID = Weighings.Session
WHERE (Sessions.DateTime >= '01/01/2011')
GROUP BY Weighings.Member
ORDER BY Weighings.Member
It returns this:
Member | FirstDate | LastDate
Blah | 01/01/11 | 06/07/11
Blah2 | 02/03/11 | 05/07/11
I need to get the value of a cell Weight_kg in table Weighings for the returned values FirstDate and LastDate to give results like so:
Member | FirstWeight | LastWeight
Blah | 150Kg | 60KG
Blah2 | 70Kg | 72KG
I have tried all combinations of things but just can't work it out, any ideas?
EDIT
Tables:
Sessions
______________________
SessionGUID | DateTime
----------------------
12432524325 | 01/01/11
12432524324 | 01/08/11
12432524323 | 01/15/11
34257473563 | 03/05/11
43634574545 | 06/07/11
Weighings
_____________________________________
Member | Session | Weight_kg
-------------------------------------
vffd8fdg87f | 12432524325 | 150
vffd8fdg87f | 12432524324 | 120
vffd8fdg87f | 12432524323 | 110
ddffv89sdv8 | 34257473563 | 124
32878vfdsv8 | 43634574545 | 75
;with C as
(
select W.Member,
W.Weight_kg,
row_number() over(partition by W.Member order by S.datetime desc) as rnLast,
row_number() over(partition by W.Member order by S.datetime asc) as rnFirst
from Weighings as W
inner join Sessions as S
on S.sessionguid = W.Session and
S.DateTime >= '20110101'
)
select CF.Member,
CF.Weight_kg as FirstWeight,
CL.Weight_kg as LastWeigth
from C as CF
inner join C as CL
on CF.Member = CL.Member
where CF.rnFirst = 1 and
CL.rnLast = 1
Try here: https://data.stackexchange.com/stackoverflow/q/118518/
You can use the RANK..OVER stmt (works only on SQL 2k5+)
select fw.Member, st.Weight, en.Weight
from
(
select Member, Weight, RANK() OVER(PARTITION BY Member ORDER BY Weight) rnk
from Weighings
) st
inner join
(
select Member, Weight, RANK() OVER(PARTITION BY Member ORDER BY WeightDESC) rnk
from Weighings
) en on en.Member= st.Member and st.rnk = 1 and en.rnk = 1
You have two possibilities.
If you want to reuse the first SELECT more times, I'd suggest to sreate temporary table
CREATE TEMPORARY TABLE `tmpTable` AS SELECT /*the first select*/ ;
/*and then*/
SELECT * FROM `tmpTable` /*the second select from the first select*/
If you require the first select only once
SELECT first.*
FROM (SELECT /*the first select*/) AS first