SQL query required [duplicate] - sql

This question already has answers here:
Single SQL query required [closed]
(3 answers)
Closed 9 years ago.
I have two tables as follows
companyid name
1 pwc
2 dell
3 microsoft
4 google
5 yahoo
6 twitter
companyid state month powerconsumption
1 newyork jan 240
2 california jan 130
3 arizona jan 210
4 texas jan 130
5 texas jan 650
6 california jan 310
2 arizona jan 340
I want to have a query to list the company in each state which consumed maximum power in the month of jan.So the result in case of above data will be
arizona dell 340
california twitter 310
newyork pwc 240
texas yahoo 650

SELECT DISTINCT (SELECT name FROM company WHERE (companyid = (SELECT TOP (1) companyid FROM consumption WHERE (state = a.state) AND (month = a.month) ORDER BY powerconsumption DESC))) AS company,
state,
month,
(SELECT TOP (1) powerconsumption FROM consumption AS consumption_1 WHERE (state = a.state) AND (month = a.month) ORDER BY powerconsumption DESC) AS powerconsumption
FROM dbo.consumption AS a

Try this query:
SELECT x.State,
c.Name AS CompanyName,
x.PowerConsumption
FROM
(
SELECT pc.CompanyID, pc.State, pc.PowerConsumption,
DENSE_RANK() OVER(PARTITION BY pc.State ORDER BY pc.PowerConsumption DESC) AS Rnk
FROM dbo.PowerConsumptionTable pc
WHERE pc.Month = 'jan'
) x INNER JOIN dbo.CompanyTable c ON x.CompanyID = c.CompanyID
WHERE x.Rnk = 1

I got an answer and that seems the best way for me. It is having a sub query,but i don't see a way to avoid that.
select t2.state,t1.name,t2.powerconsumption
FROM table1 t1
JOIN table2 t2
ON t1.companyid =t2.companyid
where t2.powerconsumption =(select MAX(t3.powerconsumption) from table2 t3 where t3.state=t2.state and t3.month='jan')
SQL Fiddle

Related

How to assign filters to row number () function in sql

I am trying to extract only single row after name = system in each case where the town is not Austin.
In case 1001 there are 8 rows, row # 4 is system, output should be only the row with Name=Terry and Date Moved=7/4/2019 (Next entry with town /= Austin)
Case Name Town Date Moved Row #(Not in table)
1001 Ted Madisson 9/7/2018 1
1001 Joyal Boston 10/4/2018 2
1001 Beatrice Chicago 1/1/2019 3
1001 System Chicago 1/5/2019 4
1001 John Austin 4/11/2019 5
1001 Simon Austin 6/11/2019 6
1001 Terry Cleveland 7/4/2019 7
1001 Hawkins Newyork 8/4/2019 8
1002 Devon Boston 12/4/2018 1
1002 Joy Austin 12/7/2018 2
1002 Rachael Newyork 12/19/2018 3
1002 Bill Chicago 1/4/2019 4
1002 System Dallas 2/12/2019 5
1002 Phil Austin 3/16/2019 6
1002 Dan Seattle 5/18/2019 7
1002 Claire Birmingham 7/7/2019 8
Tried sub query with row number function and not in ('Austin') filter
ROW_NUMBER() OVER(PARTITION BY Case ORDER BY Moved_date ASC) AS ROWNUM
Please note there are > 10k cases.
You can try this below script-
WITH CTE AS
(
SELECT [Case],[Name],Town,[Date Moved],
ROW_NUMBER() OVER (PARTITION BY [Case] ORDER BY [Date Moved]) [Row #]
FROM your_table
)
SELECT A.*
FROM CTE A
INNER JOIN
(
SELECT C.[Case],C.Town,MAX(C.[Row #]) MRN
FROM CTE C
INNER JOIN
(
SELECT *
FROM CTE A
WHERE A.Name = 'System'
)D ON C.[Case] = D.[Case] AND C.[Row #] > D.[Row #]
AND C.Town = 'Austin'
GROUP BY C.[Case],C.Town
)B ON A.[Case] = B.[Case] AND A.[Row #] = B.MRN+1
Output is -
Case Name Town Date Moved Row #
1001 Terry Cleveland 7/4/2019 6
1002 Dan Seattle 5/18/2019 7
Here are three possibilities. I'm still concerned about ties though. The first one will return multiple rows while the others only one per case:
with matches as (
select t1."case", min(t2."Date Moved") as "Date Moved"
from Movements r1 inner join Movements t2 on t1."case" = t2."case"
where t1.name = 'System' and t2.Town <> 'Austin'
and t2."Date Moved" > t1."Date Moved"
group by t1."case"
)
select t.*
from Movements t inner join matches m
on m."case" = t."case" and m."Date Moved" = t."Date Moved";
select m2.*
from Movements m1 cross apply (
select top 1 * from Movements m2
where m2.Town <> 'Austin' and m2."Date Moved" > m1."Date Moved"
order by m2."Date Moved"
) as match
where m1.name = 'System';
with m1 as (
select *,
count(case when name = 'System') over (partition by "case" order by "Date Moved") as flag
from Movements
), m2 as (
select *,
row_number() over (partition by "case" order by "Date Moved") as rn
from m1
where flag = 1 and name <> 'System' and Town <> 'Austin'
)
select * from m2 where rn = 1;
I'm basically assuming this is SQL Server. You might need a few minor tweaks if not.
It also does not require a town named Austin to fall between the "System" row and the desired row as I do not believe that was a stated requirement.

SQL: Filter (rows) with maximum value within groups (columns)

I need to filter for rows based on maximum values of version within month and location. Using SQL.
For example, I have table below where there are version 1 and 2 of June & NYC, I wanted to filter for only the row of version 2 with revenue 11. Or for January & NYC, I wanted to get only the row with revenue 15.
Month Location Version Revenue
June NYC 1 10
June NYC 2 11
June LA 3 12
January NYC 1 13
January NYC 2 14
January NYC 3 15
January LA 1 16
January LA 2 17
Result:
Month Location Version Revenue
June NYC 2 11
June LA 3 12
January NYC 3 15
January LA 2 17
Edit to change name of column to Revenue to remove confusion. I do not need the max value of revenue, only revenue that goes with max version of that month and that location.
You can also use joins as an alternative to correlated subqueries, e.g.:
select t1.* from YourTable t1 inner join
(
select t2.month, t2.location, max(t2.version) as mv
from YourTable t2
group by t2.month, t2.location
) q on t1.month = q.month and t1.location = q.location and t1.version = q.mv
Change YourTable to the name of your table.
A typical method is filtering using a correlated subquery:
select t.*
from t
where t.version = (select max(t2.version)
from t t2
where t2.month = t.month and t2.location = t.location
);
Another alternative that minimizes subqueries is to use the row_number() window function. (You don't mention which database server you're using, but most of them support it.)
SELECT month, location, version, revenue
FROM (SELECT month, location, version, revenue
, row_number() OVER (PARTITION BY month, location ORDER BY version DESC) AS rn
FROM your_table)
WHERE rn = 1;

SQL Max Value for a Specified Limit

I'm trying to return a list of years when certain conditions are met but I am having trouble with the MAX function and having it work with the rest of my logic.
For the following two tables:
coach
coach | team | wins | year
------+------+------+------
nk01 | a | 4 | 2000
vx92 | b | 1 | 2000
nk01 | b | 5 | 2003
vx92 | a | 2 | 2003
team
team | worldcupwin | year
-----+-------------+------
a | Y | 2000
b | N | 2000
a | Y | 2003
b | N | 2003
I want to get the following output:
years
-----
2000
Where the years printed are where the coaches' team with most wins during that year also won the world cup.
I decided to use the MAX function but quickly ran into the problem of not knowing how to use it to only be looking for max values for a certain year. This is what I've got so far:
SELECT y.year
FROM (SELECT c.year, MAX(c.wins), c.team
FROM coach AS c
WHERE c.year >= 1999
GROUP BY c.year, c.team) AS y, teams AS t
WHERE y.year = t.year AND t.worldcupwin = 'Y' AND y.team = t.team;
This query outputs all years greater than 1999 for me, rather than just those where a coach with the most wins also won the world cup.
(Using postgresql)
Any help is appreciated!
You can use correlated subquery
DEMO
SELECT c.year, c.team
FROM coachs AS c inner join teams t on c.team = t.team and c.year=t.year
WHERE c.year >= 1999 and exists (select 1 from coachs c1 where c.team=c1.team
having max(c1.wins)=c.wins)
and t.worldcupwin = 'Y'
OUTPUT:
year team
2000 a
The following query uses DISTINCT ON:
SELECT DISTINCT ON (year) c.year, wins, worldcupwin, c.team
FROM coach AS c
INNER JOIN team AS t ON c.team = t.team AND c.year = t.year
WHERE c.year > 1999
ORDER BY year, wins DESC
in order to return the records having the biggest number of wins per year
year wins worldcupwin team
---------------------------------
2000 4 Y a
2003 5 N b
Filtering out teams that didn't win the world cup:
SELECT year, team
FROM (
SELECT DISTINCT ON (year) c.year, wins, worldcupwin, c.team
FROM coach AS c
INNER JOIN team AS t ON c.team = t.team AND c.year = t.year
WHERE c.year > 1999
ORDER BY year, wins DESC) AS t
WHERE t.worldcupwin = 'Y'
ORDER BY year, wins DESC
gives the expected result:
year team
-------------
2000 a
Demo here
You can use the below to get the desired result:
EASY METHOD
SELECT TOP 1 c.year
FROM coach AS c INNER JOIN team AS t ON c.team = t.team AND c.year = t.year
WHERE t.worldcupwin = 'Y'
ORDER BY c.wins DESC;
use row_number() window function
select a.coach,a.team,a.win,a.year from
(select c.*,t.*,
row_number()over(order by wins desc) rn
from coach c join team t on c.team=t.team
where worldcupwin='Y'
) a where a.rn=1

How to replace all values in grouped column except first row

I have table like this:
ID Region CreatedDate Value
--------------------------------
1 USA 2016-01-01 5
2 USA 2016-02-02 10
3 Canada 2016-02-02 2
4 USA 2016-02-03 7
5 Canada 2016-03-03 3
6 Canada 2016-03-04 10
7 USA 2016-03-04 1
8 Cuba 2016-01-01 4
I need to sum column Value grouped by Region and CreatedDate by year and month. The result will be
Region Year Month SumOfValue
--------------------------------
USA 2016 1 5
USA 2016 2 17
USA 2016 3 1
Canada 2016 2 2
Canada 2016 3 13
Cuba 2016 1 4
BUT I want to replace all repeated values in column Region with empty string except first met row. The finish result must be:
Region Year Month SumOfValue
--------------------------------
USA 2016 1 5
2016 2 17
2016 3 1
Canada 2016 2 2
2016 3 13
Cuba 2016 1 4
Thank you for a solution. It will be advantage if solution will replace also in column Year
You need to use SUM and GROUP BY to get the SumOfValue. For the formatting, you can use ROW_NUMBER:
WITH Cte AS(
SELECT
Region,
[Year] = YEAR(CreatedDate),
[Month] = MONTH(CreatedDate),
SumOfValue = SUM(Value),
Rn = ROW_NUMBER() OVER(PARTITION BY Region ORDER BY YEAR(CreatedDate), MONTH(CreatedDate))
FROM #tbl
GROUP BY
Region, YEAR(CreatedDate), MONTH(CreatedDate)
)
SELECT
Region = CASE WHEN Rn = 1 THEN c.Region ELSE '' END,
[Year],
[Month],
SumOfValue
FROM Cte c
ORDER BY
c.Region, Rn
ONLINE DEMO
Although this can be done in TSQL, I suggest you do the formatting on the application side.
Query that follows the same order as the OP.

cross reference nearest date data

I have three table ElecUser, ElecUsage, ElecEmissionFactor
ElecUser:
UserID UserName
1 Main Building
2 Staff Quarter
ElecUsage:
UserID Time Amount
1 1/7/2010 23230
1 8/10/2011 34340
1 8/1/2011 34300
1 2/3/2012 43430
1 4/2/2013 43560
1 3/2/2014 44540
2 3/6/2014 44000
ElecEmissionFactor:
Time CO2Emission
1/1/2010 0.5
1/1/2011 0.55
1/1/2012 0.56
1/1/2013 0.57
And intended outcome:
UserName Time CO2
1 2010 11615
1 2011 37752 (34340*0.55 + 34300*0.55)
1 2012 24320.8
1 2013 24829.2
1 2014 25387.8
2 2014 25080
The logic is ElecUsage.Amount * ElecEmissionFactor.
If same user and same year, add them up for the record of that year.
My query is:
SELECT ElecUser.UserName, Year([ElecUsage].[Time]), SUM((ElecEmissionFactor.CO2Emission*ElecUsage.Amount)) As CO2
FROM ElecEmissionFactor, ElecUser INNER JOIN ElecUsage ON ElecUser.UserID = ElecUsage.UserID
WHERE (((Year([ElecUsage].[Time]))>=Year([ElecEmissionFactor].[Time])))
GROUP BY ElecUser.UserName, Year([ElecUsage].[Time])
HAVING Year([ElecUsage].[Time]) = Max(Year(ElecEmissionFactor.Time));
However, this only shows the year with emission factor.
The challenge is to reference the year without emission factor to the latest year with emission factor.
Sub-query may be one of the solutions but i fail to do so.
I got stuck for a while. Hope to see your reply.
Thanks
Try something like this..
-- not tested
select T1.id, year(T1.time) as Time, sum(T1.amount*T2.co2emission) as CO2
from ElecUsage T1
left outer join ElecEmissionFactor T2 on (year(T1.time) = year(T2.time))
Group by year(T1.time), T1.id
use sub query to get the corresponding factor in this way
select T1.id,
year(T1.time) as Time,
sum(T1.amount*
(
select top 1 CO2Emission from ElecEmissionFactor T2
where year(T2.time) <= year(T1.time) order by T2.time desc
)
) as CO2
from ElecUsage T1
Group by year(T1.time), T1.id