T-SQl Query Problem - sql

I have a table called CorporateTree and Production and the tables have data like:
Table: CorporateTree
DivisionName RegionName CommonName BU
Central Region 1 Raintree 101
Central Region 1 Glenwood 102
East Region 2 Balsa 201
East Region2 Warren 202
Table: Production
ProdID BU ResidentName ResidentID Room
1 101 Smith, Jeff 234859 1002-A
2 202 Mill, Steve 125467 2002-B
3 101 Sisk, Paul 4383943 1009-C
4 101 Sims, Gary 384393 1010-A
5 202 Mason, Sam 32902 1012-A
I am looking to get output like this:
Division Region Facility Business Unit ResidentCount Status
Central Region 1 Glenwood 102 0 Flag
Central Region 1 Raintree 101 3
East Region 2 Balsa 201 0 Flag
East Region 2 Warren 202 2
if the Number of Residents is zero (0) output the value of “Flag” in a Status
i tried this query:
SELECT ct.DivisionName,ct.RegionName,ct.CommonName AS Facility,ct.BU AS [Business Unit],
(SELECT ROW_NUMBER() OVER (PARTITION BY p.BU ORDER BY p.BU DESC)) AS ResidentCount FROM
CorporateTree ct INNER JOIN Production p ON
p.Bu = ct.BU
But it doesn't seem to be working? Can any one help me on this?

You'll want to use a LEFT JOIN to account for any Business Units that have no rows in the Production table.
SELECT ct.DivisionName, ct.RegionName, ct.CommonName AS Facility, ct.BU AS [Business Unit],
COUNT(p.BU) as ResidentCount,
CASE WHEN COUNT(p.BU) = 0 THEN 'Flag' ELSE '' END AS Status
FROM CorporateTree ct
LEFT JOIN Production p
ON p.BU = ct.BU
GROUP BY ct.DivisionName, ct.RegionName, ct.CommonName, ct.BU

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.

Include a column to count records with a specific value

I want to return all data in a table and append a column that counts the number of records in a subset (say, the number of houses in a neighborhood).
I tried
CASE
WHEN EXISTS (SELECT 1 as [parcels]
FROM dbo.parcels p2
WHERE p2.Neighborhood = p.Neighborhood)
THEN COUNT([parcels]) END -- can't count outside subquery
as [TotalProps]
The subquery itself returns a value of 1 for each property record in any given neighborhood, but I can't count/sum the [parcels] outside of the subquery in a THEN statement.
Input Table:
dbo.parcels
ID Address Neighborhood
== ======= ============
1 123 Main St MITO
2 124 Main St MITO
3 200 2nd St MITO
4 201 2nd St MITO
5 5 Park Ave FAIRWIND
6 1600 Baker St GALLERY
7 1601 Baker St GALLERY
8 1602 Baker St GALLERY
SELECT *, <<<COUNT(neighborhood props)>>> as [TotalProps]
FROM dbo.parcels p
Expected Output:
ID Address Neighborhood TotalProps
== ======= ============ ==========
1 123 Main St MITO 4
2 124 Main St MITO 4
3 200 2nd St MITO 4
4 201 2nd St MITO 4
5 5 Park Ave FAIRWIND 1
6 1600 Baker St GALLERY 3
7 1601 Baker St GALLERY 3
8 1602 Baker St GALLERY 3
You can use COUNT OVER PARTITION aggregate:
SELECT
p.*,
COUNT(ID) OVER(PARTITION BY Neighborhood) AS TotalProps
FROM dbo.parcels p
Use window functions:
select p.*, count(*) over (partition by neighborhood)
from dbo.parcels p;
Keeping things simple - a basic subselect will give you what you need ...
SELECT
p.*,
(
select count(*)
FROM dbo.parcels p2
WHERE p2.neighborhood = p1.neighborhood ) AS hoodcount
FROM dbo.parcels p

Retrieve combinations from different rows as inputs SQL

I am new to SQL and I am kind of stuck at an issue. I have a table with following structure... The table format is something that I cannot change. I have tried INNER joins and cross join but that did not help me much.
I have to retrieve all the records which depends on my input for example if my input will be Chicago, Sedan and chilly.
I should retrieve only combination of Chicago or Sedan or Chilly or Chicago and Sedan or Chicago and chilly and so on... for example in the following table ID 4 should not be retrieved as it is combination of new york and chilly.
Any help would be greatly appreciated.
ID TYPE CODE
1 CITY Chicago
1 CAR SEDAN
1 WEATHER CHILLY
2 WEATHER CHILLY
2 CAR SEDAN
3 CITY Chicago
4 CITY New York
4 CAR SEDAN
Sai,
You can give this a try to see if this is what you are after.
I did add one more line to your original example table just to help illustrate how this SQL would render.
ID TYPE CODE
1 CITY Chicago
1 CITY Dallas
1 CAR SEDAN
1 WEATHER CHILLY
2 WEATHER CHILLY
2 CAR SEDAN
3 CITY Chicago
4 CITY New York
4 CAR SEDAN
Using this SQL will render your table output is a more manageable format.
SELECT * FROM
((select id, type, code from TABLE1 t1)
pivot (listagg(code,',') within group (order by type)
for type in('CITY' as CITY,'CAR' as CAR, 'WEATHER' as WEATHER)))
order by id
This will turn the table format above to the following formatted record set.
ID CITY CAR WEATHER
1 Chicago,Dallas SEDAN CHILLY
2 (null) SEDAN CHILLY
3 Chicago (null) (null)
4 New York SEDAN (null)
Of course, if you wish to place quotes around each item in the output you could do this.
SELECT * FROM
((select id, type, code from TABLE1 t1)
pivot (listagg(''''||code||'''',',') within group (order by type)
for type in('CITY' as CITY,'CAR' as CAR, 'WEATHER' as WEATHER)))
order by id
This would then render as
ID CITY CAR WEATHER
1 'Chicago','Dallas' 'SEDAN' 'CHILLY'
2 (null) 'SEDAN' 'CHILLY'
3 'Chicago' (null) (null)
4 'New York' 'SEDAN' (null)
Is this more to what you are looking for?
Slight extension of Gordon's query
http://sqlfiddle.com/#!4/b844db/13
SELECT * FROM TABLE1 t1
WHERE t1.ID IN
(SELECT ID
FROM TABLE1 t2
GROUP BY ID
HAVING
SUM(CASE WHEN CODE IN ('Chicago','SEDAN','CHILLY')
THEN 1 ELSE 0 END)
= COUNT(*)
)
You can use group by and having:
select id
from t
group by id
having sum(case when code in ('Chicago', 'Sedan', 'chilly') then 1 else 0 end) = count(*);
Perhaps you intend:
having sum(case when type = 'City' and code <> 'Chicago' then 1 else 0 end) = 0 and
sum(case when type = 'Car' and code <> 'Sedan' then 1 else 0 end) = 0 and
sum(case when type = 'Weather' and code <> 'Chilly' then 1 else 0 end) = 0

How to join three tables in SQL Server 2012 and calculate ranking based on 2 attributes

I have 3 tables:
tblEmployee
E_ID E_Name E_City
--------------------------------
101 sasa Mumbai
102 sdf California
103 trt Illinois
104 dssd Texas
105 trt Pennsylvania
106 wee Arizona
107 rer Texas
108 wqe California
109 sadd Michigan
tblGen
Tgenerate is boolean value
Emp_ID Tgenerate
--------------------
105 1
108 1
102 1
102 1
102 0
104 1
107 0
108 1
109 0
And the tblStat:
Emp_ID Status
------------------
103 Pending
107 Pending
103 Pending
101 Delivered
104 Pending
104 Pending
108 Pending
101 Delivered
105 Delivered
I have to join these 3 tables and want output like this
E_Name EmployeeID City TgenerateCount Delivered_Count Ranking
TgenerateCount is calculated for every employee. It is count of TgenerateCount having value 1, for ex 102 has 2 TgenerateCount and 109 has 0 TgenerateCount.
Delivered_Count is count of Status of those who has 'Delivered' status. For ex. 101 has 2 Delivered. I want to display every user in the output table.
Any help would be greatly appreciated.
As your two fact tables have a many:1 relationship with your dimension table, you should aggregate them before joining them.
SELECT
e.*,
COALESCE(g.rows, 0) AS TgenerateCount,
COALESCE(s.rows, 0) AS DeliveredCount,
RANK() OVER (ORDER BY COALESCE(g.rows, 0) + COALESCE(s.rows,0) DESC) AS ranking
FROM
tblEmployee e
LEFT JOIN
(
SELECT E_ID, COUNT(*) AS rows FROM tblGen WHERE Tgenerate = 1 GROUP BY E_ID
)
g
ON g.E_ID = e.E_ID
LEFT JOIN
(
SELECT E_ID, COUNT(*) AS rows FROM tblStat WHERE STATUS = 'Delivered' GROUP BY E_ID
)
s
ON s.E_ID = e.E_ID
You've been unclear on how the ranking should be completed, so this simply gives an example ranking.

Using IN operator on a correlated subquery

Consider the following query on the two following Tables:
SELECT sid FROM Salesman SM WHERE sid IN(SELECT sid FROM Sale S WHERE s.sid<>sm.sid)
Sale Table
SALEID SID SLDATE
1001 1 01-Jan-14
1006 1 01-Jun-15
1003 4 01-Feb-14
1002 5 02-Jan-14
1005 2 01-Feb-14
1004 1 01-Mar-14
Salesman Table
SID SNAME LOCATION
1 Peter London
2 Michael Paris
3 John Mumbai
5 Kevin London
4 Harry Chicago
6 Alex Chicago
Why it doesn't fetch any results?
For example: on the first iteration of outer query, inner query should return 2,4,5. But it seems not. Why?
PS: Please ignore the practical use of such a query. This is for academic purpose.
Because it is impossible to fetch anything with this condition, I don't understand what you were trying to do..
As I see it you either meant to select all the sailsmans that didn't make any sales, and in that case this is the right query:
select sid from Salesman SM where sid not in (select sid from Sale S)
or you want only the salesmans that did make a sale, and in that case this is the right query:
select sid from Salesman SM where sid in (select sid from Sale S)