Use String Row As column - sql-server

I have UserExams tables shown below
I need to display like FirstName, First, Second, Final
I've tried using PIVOT but the aggregation function don't return all StudentMarks
select *
from
(
SELECT Users.FirstName,
ExamsNames.Name,
UserExams.StudentMark
FROM Exams INNER JOIN ExamsNames ON Exams.ExamNameID = ExamsNames.ExamsNamesID
INNER JOIN UserExams ON Exams.ExamID = UserExams.ExamID
INNER JOIN Users ON UserExams.UserID = Users.UserID
)t
PIVOT
(
min(StudentMark)
for Name in ([First],[Second],[Final])
)p

The way your current query is written you are going to return one min(StudentMark) for each exam in Name. If you want to return multiple values for each exam, then you will want to include another column that will give you distinct rows - I would suggest using row_number:
select FirstName, [First],[Second],[Final]
from
(
SELECT Users.FirstName,
ExamsNames.Name,
UserExams.StudentMark,
row_number() over(partition by Users.FirstName, ExamsNames.Name
order by UserExams.StudentMark) seq
FROM Exams
INNER JOIN ExamsNames ON Exams.ExamNameID = ExamsNames.ExamsNamesID
INNER JOIN UserExams ON Exams.ExamID = UserExams.ExamID
INNER JOIN Users ON UserExams.UserID = Users.UserID
)t
PIVOT
(
min(StudentMark)
for Name in ([First],[Second],[Final])
)p

Related

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.

Group nested selected query returning all rows

I'm trying to display the data so that only one line is displayed per customer, i'm having trouble with trying to achieve that with my code as its returning all records, can anyone help
SELECT customerOrdrs.NAME AS 'Name',
customerOrdrs.currentbalance -
Sum(COALESCE(customerOrdrs.revisedbalance, 0)) AS 'RevisedBalance',
sold AS 'NumberOfItemsSold'
FROM customers,
(SELECT c.NAME AS NAME,
c.balance AS CurrentBalance,
i.qty AS RevisedBalance,
( Min(s.price) * i.qty ) AS Sold
FROM customers c
INNER JOIN sales o
ON c.NAME = o.custname
INNER JOIN purchases i
ON i.orderno = o.orderno
INNER JOIN contracters s
ON i.item = s.item
GROUP BY c.NAME,
c.balance,
i.qty) customerOrdrs
GROUP BY customerOrdrs.NAME,
customerOrdrs.currentbalance,
sold
I'm not sure how your data looks but I have reformatted the query and there are a few things I've noticed off the bat.
I have removed the subquery as I don't believe it is necessary - in addition your original query is referring to customer table twice without defining a join
Select [C].[Name] As [Name]
, [CurrentBalance] = [C].[Balance]
, [RevisedBalance] = [C].[Balance] - Sum([P].[Qty])
, [Sold] = ( Min([CO].[Price]) * sum([P].[Qty]) )
From [CUSTOMERS] [C]
Inner Join [Sales] [s]
On [C].[Name] = [s].[custName]
Inner Join [Purchases] [P]
On [P].[OrderNo] = [s].[OrderNo]
Inner Join [Contracters] [CO]
On [P].[Item] = [CO].[Item]
Group By [C].[Name]
, [C].[Balance];

select count over partition by

I am learning window functions in sql server. I am using AdventrueWorks2012 database for practice. I want to calculate total number of sales and purchases for each item in the store.
The classic solution can be like
SELECT ProductID,
Quantity,
(SELECT Count(*)
FROM AdventureWorks.Purchasing.PurchaseOrderDetail
WHERE PurchaseOrderDetail.ProductID = p.ProductID) TotalPurchases,
(SELECT Count(*)
FROM AdventureWorks.Sales.SalesOrderDetail
WHERE SalesOrderDetail.ProductID = p.ProductID) TotalSales
FROM (SELECT DISTINCT ProductID,
Quantity
FROM AdventureWorks.Production.ProductInventory) p
Trying to convert to window functions gives me wrong results:
SELECT DISTINCT d.ProductID,
Quantity,
Count(d.ProductID)
OVER(
PARTITION BY d.ProductID) TotalPurchases,
Count(d2.ProductID)
OVER(
PARTITION BY d2.ProductID) TotalSales
FROM (SELECT DISTINCT ProductID,
Quantity
FROM AdventureWorks.Production.ProductInventory) p
INNER JOIN AdventureWorks.Purchasing.PurchaseOrderDetail d
ON p.ProductID = d.ProductID
INNER JOIN AdventureWorks.Sales.SalesOrderDetail d2
ON p.ProductID = d2.ProductID
ORDER BY d.ProductID
Why this is wrong? How can I correct it?
You should change INNER JOIN to LEFT JOIN
Because when you inner join, result will miss productid which from ProductInventory table does not have PurchaseOrderDetail or SalesOrderDetail.

Get Max(id) from one to many table

I know this question was asked many times but I was tring and trying without success
I have one to many relationship between two tables and some more inner-joins to get more data.
Here is my query:
SELECT
ShopOffer.OfferID,
ShopOffer.OfferMessage,
Shop.ID,
Shop.Name,
Shop.Phone,
[User].Name,
[User].UserID,
ShopOfferStatus.Name AS StatusName,
BlockedShopInUser.IsBlocked
FROM
ShopOffer
INNER JOIN ShopOfferStatus ON ShopOffer.ShopOfferStatusID = ShopOfferStatus.ShopOfferStatusID
INNER JOIN Shop ON ShopOffer.ShopID = Shop.ShopID
INNER JOIN UserRequest ON ShopOffer.UserRequestID = UserRequest.UserRequestID
INNER JOIN [User] ON UserRequest.UserID = [User].UserID
INNER JOIN BlockedShopInUser ON Shop.ShopID = BlockedShopInUser.ShopID AND [User].UserID = BlockedShopInUser.UserID
Each shop can create many offers. In that query I would like to get only the last offer for each shop.
Thanks.
Here is a way:
;WITH LastShopOffer AS
(
SELECT *,
RN = ROW_NUMBER() OVER(PARTITION BY ShopID ORDER BY OfferID DESC)
FROM ShopOffer
)
SELECT
SO.OfferID,
SO.OfferMessage,
S.ID,
S.Name,
S.Phone,
U.Name,
U.UserID,
SOS.Name AS StatusName,
B.IsBlocked
FROM ( SELECT *
FROM LastShopOffer
WHERE RN = 1) SO
INNER JOIN ShopOfferStatus SOS
ON SO.ShopOfferStatusID = SOS.ShopOfferStatusID
INNER JOIN Shop S
ON SO.ShopID = S.ShopID
INNER JOIN UserRequest UR
ON SO.UserRequestID = UR.UserRequestID
INNER JOIN [User] U
ON UR.UserID = U.UserID
INNER JOIN BlockedShopInUser B
ON S.ShopID = B.ShopID
AND U.UserID = B.UserID;
I think you have to start with Shop and then perform a CROSS APPLY on the TOP 1 record from ShopOffer:
SELECT
ShopOffer.OfferID,
ShopOffer.OfferMessage,
Shop.ID,
Shop.Name,
Shop.Phone,
[User].Name,
[User].UserID,
ShopOfferStatus.Name AS StatusName,
BlockedShopInUser.IsBlocked
FROM Shop
CROSS APPLY (
SELECT TOP 1 OfferID, OfferMessage, ShopOfferStatusID, UserRequestID
FROM ShopOffer AS s
WHERE s.ShopID = Shop.ShopID
ORDER BY s.OfferID DESC
) ShopOffer
INNER JOIN ShopOfferStatus ON ShopOffer.ShopOfferStatusID = ShopOfferStatus.ShopOfferStatusID
INNER JOIN UserRequest ON ShopOffer.UserRequestID = UserRequest.UserRequestID
INNER JOIN [User] ON UserRequest.UserID = [User].UserID
INNER JOIN BlockedShopInUser ON Shop.ShopID = BlockedShopInUser.ShopID AND [User].UserID = BlockedShopInUser.UserID

Find Max value of sum Using SQL server

I have this query i need to alter it to find the max of Sum(StudentMark)
SELECT Users.UserID,
ClassCourses.CourseID,
sum(StudentMark)SumOFMarks
FROM Users
INNER JOIN UserExams
ON Users.UserID = UserExams.UserID
INNER JOIN Exams
ON UserExams.ExamID = Exams.ExamID
INNER JOIN ClassCourses
ON Exams.ClassID = ClassCourses.ClassID
AND Exams.CourseID = ClassCourses.CourseID
GROUP BY Users.UserID,
ClassCourses.CourseID
Wrap this in a CTE and query the CTE:
;WITH MyCTE AS
(
SELECT Users.UserID,
ClassCourses.CourseID,
sum(StudentMark)SumOFMarks
FROM Users
INNER JOIN UserExams
ON Users.UserID = UserExams.UserID
INNER JOIN Exams
ON UserExams.ExamID = Exams.ExamID
INNER JOIN ClassCourses
ON Exams.ClassID = ClassCourses.ClassID
AND Exams.CourseID = ClassCourses.CourseID
GROUP BY Users.UserID,
ClassCourses.CourseID
)
SELECT MAX(SumOFMarks)
FROM MyCTE
this works good
Create procedure [dbo].[MaxMinMarks]
(
#pClassID int
)
as
--check if the table exists then if true delete it because we'll create it every time the SP run
IF EXISTS (SELECT *
FROM INFORMATION_SCHEMA.TABLES
WHERE
TABLE_NAME = 'StudentMarks')
drop table StudentMarks
SELECT ClassCourses.ClassID,ClassCourses.CourseID,ClassCourses.MaxMark,sum(StudentMark)SumOFMarks
--store result into new table
into StudentMarks
FROM Users INNER JOIN
UserExams ON Users.UserID = UserExams.UserID INNER JOIN
Exams ON UserExams.ExamID = Exams.ExamID INNER JOIN
ClassCourses ON Exams.ClassID = ClassCourses.ClassID AND Exams.CourseID = ClassCourses.CourseID
where ClassCourses.ClassID=#pClassID
group by Users.UserID, ClassCourses.ClassID,ClassCourses.CourseID,ClassCourses.MaxMark
--useing the new table we can find max and min marks
select ClassID,CourseID,MaxMark,max(SumOFMarks) highestMark,min(SumOFMarks)LowestMark from StudentMarks
group by ClassID,CourseID,MaxMark

Resources