how to group in two tables in SQl server? - sql-server

I have the following issue :
table # 1 structure :
Requests table for example have 2 columns :
Request_ID Branch_Name
1 xx
2 yy
3 xx
4 xx
5 yy
The second table : Requests_Items for example have the following columns
Request_ID Price
1 100
1 30
1 450
2 10
2 18
So i want my result set to be like :
Branch Name Num_of_Requests Total_Price
xx 3 580
Can you please help

select r.Branch_Name,
count(r.request_id) as Num_of_Requests,
sum(i.price) as Total_Price
from Requests r
left join Requests_Items i on i.Request_ID = r.Request_ID
group by r.Branch_Name

jurgen d was almost there
select r.Request_Id, r.Branch_Name,
COUNT(i.Price) as [Number of Requests],
SUM(i.Price) as [Total]
from Requests r
left join Requests_Items i
on r.Request_Id = i.Request_Id
group by r.Request_Id, r.Branch_Name

select r.Branch_Name, COUNT(ri.Request_ID) as Num_of_Requests, SUM(ri.Price) as Total_Price
from dbo.Requests r
left join dbo.Requests_Items ri
on r.Request_ID = ri.Request_ID
group by r.Branch_Name

Let this is my [Employees] Table
Here is my Dept table
I want the output like this using join and group by
So here is the Query for this-
select max(e.salary) as maxsalary,d.Dept from Employees e inner join DEpt d on e.DeptId=d.id group by e.DeptId,d.Dept
enter code here

Related

T-SQL query to show all the past steps, active and future steps

I have 3 tables in SQL Server:
map_table: (workflow map path)
stepId step_name
----------------
1 A
2 B
3 C
4 D
5 E
history_table:
stepId timestamp author
----------------------------
1 9:00am John
2 9:20am Mary
current_stageTable:
Id currentStageId waitingFor
------------------------------------
12345 3 Kat
I would like to write a query to show the map with the workflow status. Like this result here:
step name time author
----------------------------
1 A 9:00am John
2 B 9:20am Mary
3 C waiting Kat
4 D
5 E
I tried left join
select
m.stepId, m.step_name, h.timestamp, h.author
from
map_table m
left join
history_table h on m.stepId = h.stepId
I thought it will list all the records from the map table, since I am using left join, but somehow it only shows 3 records which is from history table..
So I changed to
select
m.stepId, m.step_name, h.timestamp, h.author
from
map_table m
left join
history_table h on m.stepId = h.stepId
union
select
m.stepId, m.step_name, '' as timestamp, '' as author
from
map_table m
where
m.stageId not in (select stageId from history_table)
order by
m.stepId
Then it list the result almost as I expected, but how do I add the 3rd table in to show the current active stage?
Thank you very much for all your help!! Much appreciated.
Looks like it's what you asked:
with map_table as (
select * from (values (1,'A')
,(2,'B')
,(3,'C')
,(4,'D')
,(5,'E')) t(stepId, step_name)
)
, history_table as (
select * from (values
(1,'9:00am','John')
,(2,'9:20am','Mary')) t(stepId, timestamp, author)
)
, current_stapeTable as (
select * from (values (2345, 3, 'Kat')) t(Id, currentStageId, waitingFor)
)
select
m.stepId, m.step_name
, time = coalesce(h.timestamp, case when c.waitingFor is not null then 'waiting' end)
, author = coalesce(h.author, c.waitingFor)
from
map_table m
left join history_table h on m.stepId = h.stepId
left join current_stapeTable c on m.stepId = c.currentStageId
I think a union fits well with the data and avoids the coalescing the values on multiple joins.
with timeline as (
select stepId, "timestamp" as ts, author from history_table
union all
select currentStageId, 'waiting', waitingFor from current_stageTable
)
select step_id, step_name, "timestamp", author
from
map_table as m left outer join timeline as t
on t.stepId = m.stepId

SQL query to show good records as well as null records

My query works perfectly well to find records with real values, however, I also need my query to show records with null values. So far my attempts at recreating this query to also show null values has resulted in losing at least 1 of my columns of results so now I'm looking for help.
This is my query so far:
SELECT sq.*, sq.TransactionCountTotal - sq.CompleteTotal as InProcTotal from
(
select
c.CustName,
t.[City],
sum (t.TransactionCount) as TransactionCountTotal
sum (
case
when (
[format] in (23,25,38)
or [format] between 400 and 499
or format between 800 and 899
)
then t.TransactionCount
else 0
end
) as CompleteTotal
FROM [log].[dbo].[TransactionSummary] t
INNER JOIN [log].[dbo].[Customer] c
on t.CustNo = c.CustNo
and t.City = c.City
and t.subno = c.subno
where t.transactiondate between '7/1/16' and '7/11/16'
group by c.CustName,t.City
) sq
This is currently what my query results show:
CustName City InProcTotal TransactionCountTotal Complete Total
Cust 1 City(a) 23 7 30
Cust 2 City(b) 74 2 76
Cust 3 City(c) 54 4 58
This is what I want my query results to show:
CustName City InProcTotal TransactionCountTotal Complete Total
Cust 1 City(a) 23 7 30
Cust 2 City(b) 74 2 76
Cust 3 City(c) 54 4 58
Cust 4 City(d) 0 0 0
Cust 5 City(e) 0 0 0
I suggest you use RIGHT JOIN in the place of INNER JOIN. You should then retain the rows from Customer that don't have matching rows in TransactionSummary.
You may also want to refactor the query like this so you use LEFT JOIN. The next person to work on the query will thank you; LEFT JOIN operations are more common.
FROM [log].[dbo].[Customer] c
LEFT JOIN [log].[dbo].[TransactionSummary] t
on t.CustNo = c.CustNo
and t.City = c.City
jwabsolution, your issue stems from grabbing all transactions instead of all customers. My mind works in this way: you want to select all of the customers & find all transaction states. Therefore, you should be selecting from the customer table. Also, you shouldn't use the INNER JOIN or you will ignore any customers that don't have transactions. Instead, use left join the transactions table. In this manner, you will retrieve all customers (even those with no transactions). Here is a good visual for SQL joins: http://www.codeproject.com/KB/database/Visual_SQL_Joins/Visual_SQL_JOINS_orig.jpg
So your query should look like this:
SELECT sq.*, sq.TransactionCountTotal - sq.CompleteTotal as InProcTotal from
(
select
c.CustName,
t.[City],
sum (t.TransactionCount) as TransactionCountTotal
sum (
case
when (
[format] in (23,25,38)
or [format] between 400 and 499
or format between 800 and 899
)
then t.TransactionCount
else 0
end
) as CompleteTotal
FROM [log].[dbo].[Customer] c
LEFT JOIN [log].[dbo].[TransactionSummary] t
on c.CustNo = t.CustNo
and c.City = t.City
and c.subno = t.subno
where t.transactiondate between '7/1/16' and '7/11/16'
group by c.CustName,t.City
) sq
Fixed it. Needed to use coalesce to get the values to show up properly.
Also added a "where" option if I want to query individual customers
SELECT sq.* ,sq.TransactionCountTotal - sq.CompleteTotal as [InProcTotal]
from
(
select
c.custname
,c.port
,sum(coalesce(t.transactioncount,0)) as TransactionCountTotal
,sum(
case when (
[format]in(23,25,38)
or[format]between 400 and 499
or[format]between 800 and 899)
then t.TransactionCount
else 0
end) as CompleteTotal
from log.dbo.customer c
left join log.dbo.TransactionSummary t
on c.custNo=t.custno
and c.subno=t.subno
and c.city=t.city
and t.transactiondate between '7/1/16' and '7/12/16'
/*where c.custname=''*/
group by c.custname,c.city
) sq

Get distinct data from 2 tables using join

Below is my query . I take socail sercurity no from Employee table and match it with child_excel table. Using that I get Employee ID and matching that with EmployeeCh table (which has employee ID). The employee has 2 child's so when I put the gender clause I get 4 records 2 for each child with different (i.e Male, Female) for each of the child's. I want only 2 rows for child 1 for each child with their respective genders.
SELECT distinct
[SSN],
empch2.GenderID,
gen.Name1
FROM [child_excel] as t
INNER JOIN Employee as empch on t.SSN = empch.SocialSecurityNo
INNER JOIN EmployeeCh as empch2 on empch.ID = empch2.EmployeeID
INNER JOIN Gender as gen on empch2.GenderID = gen.ID
I am getting O/p as
12345 1 Male
12345 2 Female
99999 1 Male
99999 2 Female
Expected output is
12345 1 Male
99999 2 Female
But when I add First Name in the join it gives proper output. I dnt want to use first Name
SELECT distinct
[SSN],
empch2.GenderID,
gen.Name1
FROM [child_excel] as t
INNER JOIN Employee as empch on t.SSN = empch.SocialSecurityNo
INNER JOIN EmployeeCh as empch2 on empch.ID = empch2.EmployeeID and t.First_Name= empch2.FirstName
INNER JOIN Gender as gen on empch2.GenderID = gen.ID
Use ROW_NUMBER ()
Select * from (
SELECT distinct
[SSN],
empch2.GenderID,
gen.Name1,
ROW_NUMBER()OVER(PARTITION BY [SSN] ORDER BY empch2.GenderID)RN
FROM [child_excel] as t
INNER JOIN Employee as empch on t.SSN = empch.SocialSecurityNo
INNER JOIN EmployeeCh as empch2 on empch.ID = empch2.EmployeeID and t.First_Name= empch2.FirstName
INNER JOIN Gender as gen on empch2.GenderID = gen.ID )T
WHERE T.RN = 1

SQL Server - Struggling to group/sum values across multiple related tables

I'm running this query:
SELECT
g.PartNum,
g.Supplier,
(g.InitialQuantityToInventory + SUM(COALESCE(t.AmountInventoryAdjusted + t.AmountReturned, 0))) AS StockLevel
FROM
GoodsIn g
LEFT JOIN
Transfers t ON g.GoodsInNumber = t.GoodsInNumber
WHERE
g.PartNum = '123'
GROUP BY
g.PartNum, g.Supplier, g.InitialQuantityToInventory
And it's returns these results:
123,SUP1,67
123,NULL,18
123,NULL,0
123,NULL,45
123,NULL,0
However I would like the StockLevel (in the 3rd column) to SUM on the supplier name, even when it's null, so that my expected result should be:
123,SUP1,67
123,NULL,63
What am I doing wrong? The query should (across all GoodsIn Numbers that have the same PartNumber & Supplier) Sum the InitialQuantities and their Amounts Adjusted & Returned for each transfer associated with the GoodsIn record.
This is the data for that part & supplier in the GoodsIn Table:
GINum Part Num Supplier InitialQuantityToInventory
73367 123 NULL 81
73570 123 NULL 18
74154 123 NULL 320
74835 123 Sup1 0
74836 123 NULL 500
75738 123 Sup1 0
And this is the corresponding rows from the Transfers table (T being short for TransferNum):
GINum T Adj Ret
73367 1 -81 0
74154 1 -200 0
74154 2 -120 45
74835 1 67 0
74836 1 -500 0
75738 1 -300 0
75738 2 300 0
Do you need to not group by InitialQuantityToInventory?
;WITH Logs (Supplier, Initial, StockChange)
AS
(
SELECT
g.Supplier,
g.InitialQuantityToInventory,
(SUM(COALESCE(t.AmountInventoryAdjusted + t.AmountReturned,0))) AS StockChange
FROM
GoodsIn g
LEFT JOIN
Transfers t ON g.GoodsInNumber = t.GoodsId
GROUP BY
g.Supplier, g.InitialQuantityToInventory
)
SELECT
Supplier,
SUM(Initial) + SUM(StockChange) AS StockLevel
FROM
Logs
GROUP BY
Supplier
What might be happening is you're getting a row per unique InitialQuantityToInventory, but from what I gather, you want these to be summed, right?
This could probably be optimised further (and probably doesn't need a CTE), but hopefully it at least returns the data you expect.
I don't think you need to GROUP BY InitialQuantityToInventory. Try following query and let me know if this works for what you need.
SELECT
g.PartNum,
g.Supplier,
MAX(g.InitialQuantityToInventory) + SUM(COALESCE(t.AmountInventoryAdjusted + t.AmountReturned,0)) AS StockLevel
FROM
GoodsIn g
LEFT JOIN
Transfers t ON g.GoodsInNumber = t.GoodsInNumber
WHERE
g.PartNum = '123'
GROUP BY
g.PartNum, g.Supplier
Try this, group the Transfers before joining and grouping
SELECT
g.PartNum,
g.Supplier,
SUM(g.InitialQuantityToInventory + COALESCE(t.adjRet, 0))
FROM Goodsin g
LEFT JOIN
(
SELECT GINum, SUM(AmountInventoryAdjusted + AmountReturned) AS adjRet
FROM Transfers
GROUP BY GINum
) T
ON t.GINum = g.GiNum
GROUP BY g.PartNum, g.Supplier

how to sort according to special case in sql

I have this case
i have stored procedure get all persons as couples male and female
i want to sort those couple according to male name
i try some sing like that
SELECT P.GenderTypeID,
Couple.CoupleID,
P.PersonID ,
p.NameAr,
p.NameEn ,
p.Mobile
FROM tbl_Couples Couple
LEFT OUTER JOIN tbl_Persons P
ON P.CoupleID = Couple.CoupleID
ORDER BY
CASE WHEN P.GenderTypeID = 1
THEN '1'--Male
WHEN P.GenderTypeID = 2
THEN '2'--Female
ELSE P.GenderTypeID END ASC ,
p.NameAr
put it get male first then female
i get that
GenderTypeID CoupleID PersonID NameAr NameEn Mobile
1 3 10 أحمد Ali 01255678668
1 5 15 سمير Samier 01255353563
1 4 17 سيد Said 012359989744
2 5 14 سامية Samia 01156786868
2 4 16 سعاد Suadd 01353563563
2 3 12 منى Mona 010264646444
put i expect
GenderTypeID CoupleID PersonID NameAr NameEn Mobile
1 3 10 أحمد Ali 01255678668
2 3 12 منى Mona 010264646444
1 5 15 سمير Samier 01255353563
2 5 14 سامية Samia 01156786868
1 4 17 سيد Said 012359989744
2 4 16 سعاد Suadd 01353563563
Use a CTE to first select only the males, which you then join with the tbl_Couples and tbl_Persons tables, which will give a result set in which the male part of the couple is duplicated for the "males" CTE.
WITH tbl_MaleOnly
AS
(
SELECT *
FROM tbl_Persons
WHERE GenderTypeID = 1
)
SELECT P.GenderTypeID,
Couple.CoupleID,
P.PersonID ,
p.NameAr,
p.NameEn ,
p.Mobile
FROM tbl_MaleOnly Male
LEFT OUTER JOIN tbl_Couples Couple
ON Couple.CoupleID = Male.CoupleID
LEFT OUTER JOIN tbl_Persons P
ON P.CoupleID = Couple.CoupleID
ORDER BY Male.NameAr
, P.GenderTypeID
Instead of a CTE, you could also use an inline view: replace "tbl_MaleOnly" in the main select with the CTE select in parenthesis.
You don't need to use any case statement in your order by clause, Just use this
SELECT P.GenderTypeID,
Couple.CoupleID,
P.PersonID ,
p.NameAr,
p.NameEn ,
p.Mobile
FROM tbl_Couples Couple
LEFT OUTER JOIN tbl_Persons P
ON P.CoupleID = Couple.CoupleID
ORDER BY P.GenderTypeID, p.NameAr
Or if you want to order your record by CoupleID just change the order by
ORDER BY Couple.CoupleID, p.NameAr

Resources