multiple count in a sql query - sql-server

i need a report from a database where i need the final result like
Number of Male, Number of Female, showing against city and finally against State.
I started off with something like.
SELECT p.StateName, d.CityName,
count(api.Gender) as Gender
FROM dbo.Application_Personal_information as api INNER JOIN
dbo.state as p ON api.State = p.ID INNER JOIN
dbo.City as d ON api.City= d.ID
group by p.StateName, d.CityName
when i do this
SELECT p.StateName, d.CityName,
count(api.Gender = 'Male) as Male,
count(api.Gender = 'Female) as Female,
FROM dbo.Application_Personal_information as api INNER JOIN
dbo.state as p ON api.State = p.ID INNER JOIN
dbo.City as d ON api.City= d.ID
group by p.StateName, d.CityName
it give's me error.
incorrect syntax near =.
i also tried with select statement
COUNT(select api.Gender from api where api.Gender ='Male') as Male,
But it is also not working.
...
Any idea?

SELECT
p.StateName, d.CityName,
sum(case when Gender ='Male' then 1 else 0 end ) as Male_count,
sum(case when Gender ='Female' then 1 else 0 end ) as Female_count
FROM
dbo.Application_Personal_information as api INNER JOIN
dbo.state as p ON api.State = p.ID INNER JOIN
dbo.City as d ON api.City= d.ID
group by
p.StateName, d.CityName

You could try the PIVOT function if you are using SQL Server 2005 or later:
WITH CTE AS
( SELECT p.StateName,
d.CityName,
api.Gender
FROM dbo.Application_Personal_information as api
INNER JOIN dbo.state as p
ON api.State = p.ID
INNER JOIN dbo.City as d
ON api.City= d.ID
)
SELECT *
FROM CTE
PIVOT
( COUNT(Gender)
FOR Gender IN ([Male], [Female])
) pvt

Related

SQL Server : left join - check for right table column value is null

I have a query as follows:
select --this select should always give me 1 record
tbl1.Id, tbl1.Name, tbl1.Address, tbl2.relNo,
CASE WHEN tbl3.Comments IS NOT NULL THEN 1 ELSE 0 END AS 'Required'
from
table1 tbl1
inner join
table2 tbl2 on tbl2.Id = tbl1.Id
left join -- This left join table gives me 5 records for one instance
(select
R.Id, C.Comments
from
tblC C
inner join
tblR R on R.Id = C.id) tbl3 on tbl3.Id = tbl2.Id
I want to write a CASE statement on the rows my left join is giving to check for null value as above and my final select query always return only 1 row. Is there a way to check if all five Comments Column values from my left join be checked for NULLs in the above query?
I would take a shortcut an use a COUNT() OVER PARTITION
CASE WHEN COUNT(*) OVER (PARTITION BY tbl3.Id) =0 THEN 0 ELSE 1 END AS 'Required'
You would have to DISTINCT your output above. Another option would be to GROUP BY and filter in the HAVING clause.
select --this select should always give me 1 record
tbl1.Id, tbl1.Name, tbl1.Address, tbl2.relNo
From table1 tbl1
inner join table2 tbl2 on tbl2.Id = tbl1.Id
left join (-- This left join table gives me 5 records for one instance
SELECT R.Id,
C.Comments
FROM tblC C
INNER JOIN tblR R on R.Id = C.id
) tbl3 on tbl3.Id = tbl2.Id
GROUP BY
Id, Name, Address, relNo
HAVING
COUNT(*) = 5
Is this what you're looking for?
(CASE WHEN (select count(tbl3.id) FROM tbl3 WHERE tbl3.Comments IS NULL) then 1 else 0 end) as 'RequiredVal'
select --this select should always give me 1 record
tbl1.Id, tbl1.Name, tbl1.Address, tbl2.relNo,
CASE WHEN tbl3.Comments IS NOT NULL THEN 1 ELSE 0 END AS 'Required'
, (CASE WHEN (select count(tbl3.id) FROM tbl3 WHERE tbl3.Comments IS NULL) then 1 else 0 end) as 'RequiredVal'
From table1 tbl1
inner join table2 tbl2 on tbl2.Id = tbl1.Id
left join (-- This left join table gives me 5 records for one instance
SELECT R.Id,
C.Comments
FROM tblC C
INNER JOIN tblR R on R.Id = C.id
) tbl3 on tbl3.Id = tbl2.Id

How can I efficiently use join and pivot in my SQL code

I have 3 tables. The query returned the desired result just the sorting of records. I added Order By but it did not work.
Result should be:
I got the result it is just the sorting of records. I want to order by the ID but it is not working.
QUERY:
WITH NAMES AS (
SELECT
P.NAMES,
P.CODE,
Q.NUM_TYP,
Q.PHONE_NUM
FROM
dbo.NAMES P
INNER JOIN dbo.PHONE Q
ON P.ID = Q.ID
LEFT JOIN DBO.ADDRESS S
ON P.PRSN_IK = S.PRSN_IK
WHERE S.ADDR Is Null
)
SELECT *
FROM
NAMES
PIVOT (Max(PHONE_NUM) FOR NUM_TYP IN (WORK, HOME)) R;
Appreciate any input. Thanks.
try trhis :
select f1.Name, nullif(f1.code, '') Code ,
isnull(f2.phone_num, 'N/A') work_phone_num, isnull(f3.phone_num, 'N/A') home_phone_num
from Names f1
left outer join Phone f2 on f1.id=f2.id and f2.Num_type='WORK'
left outer join Adress f2b on f2.id=f2b.id and f2.num_type=f2b.add_type
left outer join Phone f3 on f1.id=f3.id and f3.Num_type='HOME'
left outer join Adress f3b on f3.id=f3b.id and f3.num_type=f3b.add_type
where f2b.id is null or f3b.id is null
given that your query is working, this should work :
;WITH NAMES AS (
SELECT
P.NAMES,
P.CODE,
Q.NUM_TYP,
Q.PHONE_NUM
FROM dbo.NAMES P
INNER JOIN dbo.PHONE Q
ON P.ID = Q.ID
LEFT JOIN DBO.ADDRESS S
ON P.PRSN_IK = S.PRSN_IK
WHERE S.ADDR Is Null
), PIVOTED
AS
(
SELECT *
FROM NAMES
PIVOT (Max(PHONE_NUM) FOR NUM_TYP IN (WORK, HOME)) R
)
SELECT * FROM PIVOTED piv
inner join [dbo].[NAMES] nam
on piv.names = nam.names
ORDER BY nam.ID
I have included P.ID and wrapped everything under subquery.

only 1 value returns with sql query

AdventureWorks2012 DB - I am trying to return top 1 or 2 emlpoyees from Finance dept and Engineer dept who have worked longest. I cant get my query to return both, only results from engineering show. Any suggestions?
SELECT TOP 2 EDH.StartDate, E.BusinessEntityID, D.Name, EDH.EndDate, DATEDIFF(hour,EDH.StartDate, GETDATE()) AS HoursWorked
FROM HumanResources.Employee E
INNER JOIN Person.Person PP ON E.BusinessEntityID = PP.BusinessEntityID
INNER JOIN HumanResources.EmployeeDepartmentHistory EDH ON E.BusinessEntityID = EDH.BusinessEntityID
INNER JOIN HumanResources.Department D ON D.DepartmentID = EDH.DepartmentID
WHERE (D.Name LIKE 'Finance' OR D.Name = 'Engineering')
AND EDH.EndDate IS NULL
GROUP BY D.Name, EDH.StartDate,E.BusinessEntityID,EDH.EndDate
ORDER BY EDH.StartDate ASC
Your problem is that the employees from Engineering happen to have started before the employees from Finance. The ORDER BY is affecting all of your records (both departments), and then the TOP 2 value is grabbing the two most recent employees, regardless of departments.
If you are trying to write a query that returns the first employee from each department, you're going to have to get a bit more complex. Here is an example that uses the ROW_NUMBER() function to order employees within each department by their start date, then filters those records to only return employees who are the first individuals in their department.
SELECT
StartDate,
BusinessEntityID,
Name,
EndDate,
HoursWorked
FROM
(
SELECT
EDH.StartDate,
E.BusinessEntityID,
D.Name,
EDH.EndDate,
DATEDIFF(hour,EDH.StartDate, GETDATE()) AS HoursWorked,
ROW_NUMBER() OVER (PARTITION BY D.Name ORDER BY EDH.StartDate) AS RowNumberWithinDepartment
FROM
HumanResources.Employee E
INNER JOIN
Person.Person PP ON E.BusinessEntityID = PP.BusinessEntityID
INNER JOIN
HumanResources.EmployeeDepartmentHistory EDH ON E.BusinessEntityID = EDH.BusinessEntityID
INNER JOIN
HumanResources.Department D ON D.DepartmentID = EDH.DepartmentID
WHERE
(D.Name LIKE 'Finance' OR D.Name = 'Engineering') AND
EDH.EndDate IS NULL
GROUP BY D.Name, EDH.StartDate,E.BusinessEntityID,EDH.EndDate
) x
WHERE RowNumberWithinDepartment = 1
ORDER BY StartDate ASC

SQL query to fetch repeat column values within time frame

I have an eCommerce website where I am getting lot of fraud orders.. I'd like to pull out those Order_No.
Here is my query
SELECT
O.Order_No, O.Customer_ID, O.DateOrdered, O.IPAddress,
C.FirstName, C.LastName, CD.nameoncard
FROM
Order_No O
INNER JOIN
CardData CD ON O.card_id = CD.id
INNER JOIN
Customers C ON O.customer_id = C.customer_id
ORDER BY
O.order_no desc
Here's the criteria I want to follow:
If the customer_id repeats more than once in 6hrs
If the IPAddress repeats more than once in 6hrs
If the Lastname is NOT found in Nameoncard
Can someone help please?
can you try this
WITH Tmp (Order_No, Customer_id, DateOrdered, IPAddress, FirstName, LastName, NameOnCard)
AS
(
SELECT Ord.Order_No, Ord.Customer_Id, Ord.DateOrdered, Ord.IPAddress,
Cust.FirstName, Cust.LastName, CustData.NameOnCard
FROM Order_No Ord
INNER JOIN Customers Cust
ON
Cust.Customer_Id = Ord.Customer_Id
INNER JOIN
CardData CustData
ON CustData.Id = Ord.Card_Id
)
SELECT DISTINCT a.*
FROM Tmp a
INNER JOIN Tmp b
ON a.Order_No <> b.Order_No
AND a.Customer_Id = b.Customer_Id
WHERE DATEDIFF(hour, a.DateOrdered, b.DateOrdered) >= 6
UNION
SELECT DISTINCT c.*
FROM Tmp c
INNER JOIN Tmp d
ON c.Order_No <> d.Order_No
AND c.IPAddress = d.IPAddress
WHERE DATEDIFF(hour, c.DateOrdered, d.DateOrdered) >= 6
UNION
SELECT DISTINCT e.*
FROM Tmp e
WHERE ISNULL(e.NameOnCard,'') = ''
here is the query:
select * from
(
select b.order_no,b.dateordered,a.customer_id, C.FirstName, C.LastName, cd.nameoncard from order_no as a
left join order_no as b on a.customer_id=b.customer_id
inner join carddata as cd on b.customer_id=cd.customer_id
INNER JOIN Customers C ON b.customer_id = C.customer_id
where a.order_no < b.order_no
and datediff(hour,a.dateordered,b.dateordered) between 0 and 6
union
select b.order_no,b.dateordered,a.customer_id, C.FirstName, C.LastName, cd.nameoncard from order_no as a
left join order_no as b on a.IPAddress=b.IPAddress
inner join carddata as cd on b.customer_id=cd.customer_id
INNER JOIN Customers C ON b.customer_id = C.customer_id
where a.order_no < b.order_no
and datediff(hour,a.dateordered,b.dateordered) between 0 and 6
union
select a.order_no,a.dateordered,a.customer_id, C.FirstName, C.LastName, cd.nameoncard from order_no as a
inner join carddata as cd on a.customer_id=cd.customer_id
INNER JOIN Customers C ON a.customer_id = C.customer_id
where charindex(C.LastName,cd.nameoncard) = 0
) as abc

sql server 2008, how to get rid of duplications when inner join 3 tables

here's my query. when I inner join 2 tables, there's no problem.
SELECT S.* ,
U.Avatar ,
U.Displayname ,
ROW_NUMBER() OVER ( ORDER BY S.Id DESC ) rownum
FROM dbo.Smoothie AS S
INNER JOIN dbo.[User] AS U ON S.UserId = U.Id
WHERE S.IsPublic = 1
AND S.Status = 3
AND S.UserId = 2
then, I added another inner join. now, I got alot duplications.
SELECT S.* ,
U.Avatar ,
U.Displayname,
ROW_NUMBER() OVER ( ORDER BY S.Id DESC ) rownum
FROM dbo.Smoothie AS S
INNER JOIN dbo.[User] AS U ON S.UserId = U.Id
INNER JOIN dbo.Favorite AS F ON U.Id = F.UserId
WHERE S.IsPublic = 1
AND S.Status = 3
AND F.UserId = 2
one solutions is to use distinct. however, I have to comment out row_number, i need that row_number to do paging. is there another way to get rid of duplication?
SELECT DISTINCT S.* ,
U.Avatar ,
U.Displayname
-- ROW_NUMBER() OVER ( ORDER BY S.Id DESC ) rownum
FROM dbo.Smoothie AS S
INNER JOIN dbo.[User] AS U ON S.UserId = U.Id
INNER JOIN dbo.Favorite AS F ON U.Id = F.UserId
WHERE S.IsPublic = 1
AND S.Status = 3
AND F.UserId = 2
Why not use the query you have, without the row_number as a subquery, then add the row number back later:
SELECT *,
ROW_NUMBER() OVER ( ORDER BY subQuery.Id DESC ) rownum
FROM (
SELECT DISTINCT S.* ,
U.Avatar ,
U.Displayname
FROM dbo.Smoothie AS S
INNER JOIN dbo.[User] AS U ON S.UserId = U.Id
INNER JOIN dbo.Favorite AS F ON U.Id = F.UserId
WHERE S.IsPublic = 1
AND S.Status = 3
AND F.UserId = 2
) AS subQuery
Dense_Rank would also do the job with the your otherwise unmodified query.

Resources