RowNumber not working in Count Case - tsql

I have this to count the number of book where status 'OnShelf'
select
BookTitleID,
BookTitle,
CallNumber,
FullName,
count(case Status when 'OnShelf' then 1 else null end) AS CopiesOnShelves,
from
(
select
Book.BookTitleID,
BookTitles.BookTitle,
BookTitles.CallNumber,
Book.Status,
FullName = LastName + ', ' + FirstName + ' ' + MiddleName,
From
Book
left outer join
BookTitles
on BookTitles.BookTitleID = Book.BookTitleID
left outer join
Authors
on Authors.AuthorID = BookTitles.AuthorID
) sub
Group By Callnumber, BookTitle, BookTitleID, FullName
Sample Output
BookTitleID BookTitle CallNumber Fullname CopiesOnShelves
1 sample test test 3
But when I include the row number in the select statement it give me wrong output
select
BookTitleID,
BookTitle,
CallNumber,
FullName,
count(case Status when 'OnShelf' then 1 else null end) AS CopiesOnShelves,
r
from
(
select
Book.BookTitleID,
BookTitles.BookTitle,
BookTitles.CallNumber,
Book.Status,
FullName = LastName + ', ' + FirstName + ' ' + MiddleName,
r = row_number() over (order by Book.BookTitleID)
From
Book
left outer join
BookTitles
on BookTitles.BookTitleID = Book.BookTitleID
left outer join
Authors
on Authors.AuthorID = BookTitles.AuthorID
) sub
Group By Callnumber, BookTitle, BookTitleID, FullName, r
Sample Output
BookTitleID BookTitle CallNumber Fullname CopiesOnShelves R
1 sample test test 1 1
1 sample test test 1 2
1 sample test test 1 3

select
row_number() over (order by BookTitle) AS Row,
BookTitleID,
BookTitle,
CallNumber,
FullName,
count(case Status when 'OnShelf' then 1 else null end) AS CopiesOnShelves
from
(
select
Book.BookTitleID,
BookTitles.BookTitle,
BookTitles.CallNumber,
Book.Status,
FullName = LastName + ', ' + FirstName + ' ' + MiddleName
From
Book
left outer join
BookTitles
on BookTitles.BookTitleID = Book.BookTitleID
left outer join
Authors
on Authors.AuthorID = BookTitles.AuthorID ) sub
Group By Callnumber, BookTitle, BookTitleID, FullName
Got the right output but i got new problem Row-Number in Between Sub Query

Related

Refine data elements using having clause tsql

I'm trying to pull a dataset that returns records ONLY when there are two QUALIFERs present. I've tried left joins, populating data in temp tables then manipulating something, then numerous having clauses (resulting in subquery selects, and additional groups). I would appreciate any assistance on what I can do further.
Query:
Select E, CASE WHEN QUALIFER = '1' THEN 'NAME1' WHEN QUALIFER = '2' then 'NAME2' ELSE 'FINALNAME' END AS TYPE, count(rt.ID) 'Number '
from TABLE_ONE co (nolock)
join TABLE_TWO rt (nolock)
on co.ID = rt.ID
where co.E in (select * from #tempEmail)
AND convert(date,co.INSERTED_TIMESTAMP)between '1/1/2020' and '8/15/2020'
AND TRANS_STATUS = 'APPROVED'
group by E, QUALIFER
order by E, QUALIFER
Current resultset:
E TYPE Number
FAKEEMAIL1#Gmail NAME1 1
FAKEEMAIL1#Gmail NAME2 1
otheremailj#gmail.com Name1 21
Desired resultset:
E TYPE Number
FAKEEMAIL1#Gmail NAME1 1
FAKEEMAIL1#Gmail NAME2 1
Thank you.
Let's try the below query. I used a temp table to make things more simple for my mind.
if object_id('tempdb.dbo.#email') is not null drop table #email
create table #email
(
email varchar(50),
typeValue varchar(15),
Number int
)
insert into #email(email, typeValue, Number)
Select
E,
CASE WHEN QUALIFER = '1' THEN 'NAME1' WHEN QUALIFER = '2' then 'NAME2' ELSE 'FINALNAME' END AS TYPE,
count(rt.ID) 'Number '
from TABLE_ONE co (nolock)
join TABLE_TWO rt (nolock)
on co.ID = rt.ID
where co.E in (select * from #tempEmail)
AND convert(date,co.INSERTED_TIMESTAMP)between '1/1/2020' and '8/15/2020'
AND TRANS_STATUS = 'APPROVED'
group by E, QUALIFER
select a.email, a.typeValue
from #email a
inner join
(
select email, typeValue, rank() over (partition by email order by typeValue) as typeCount
from #email t
) as b
on b.email = a.email
and b.typeCount > 1

SQL adding numbers column

Let's say I have a table:
Table1
ID | Table2_ID | Title
1 1 Breaking_Bad
2 1 Breaking_Bad
3 2 Simpsons
4 1 House_Of_Cards
I want to rename the title by adding '_XX' (where XX is a number) to only to those entries that are the same title and have the same Table2_ID.
So end results would be
Table1
ID | Table2_ID | Title
1 1 Breaking_Bad_01
2 1 Breaking_Bad_02
3 2 Simpsons
4 1 House_Of_Cards
How could I do this with TSQL?
You can do this with
WITH T
AS (SELECT *,
COUNT(*) OVER (PARTITION BY Table2_ID, Title) AS Cnt,
ROW_NUMBER() OVER (PARTITION BY Table2_ID, Title ORDER BY ID) AS RN
FROM Table1)
UPDATE T
SET Title = Title + '_' + FORMAT(RN, 'D2')
WHERE Cnt > 1;
SQL Fiddle
Or if you are on a version without FORMAT
SET Title = Title + CASE WHEN RN < 10 THEN '_0' ELSE '_' END + CAST(RN AS VARCHAR(10))
Will this work in SQL Server? The padding to 2 digits would be straightforward.
UPDATE TABLE1 A SET TITLE = TITLE + '_' + (SELECT COUNT(*) FROM TABLE1 B WHERE A.TITLE=B.TITLE AND A.ID<=B.ID) WHERE A.ID IN (SELECT B.ID FROM TABLE1 B
WHERE A.Id<>B.ID and A.TITLE=B.TITLE)

Filter Out a Specific result from a complicated SQL statement and clean up my SQL

I am taking a combination of the following tables to determine, in and out time, total hours worked for the day, workcenter and associated pay rates. However, when the PunchType = '303' there is two rows, 1 for the initial workcenter as a '10' punch and then the '303' When the '303 punch exists I need to use that as the in punch instead. The below query and sample results show that I have narrowed my query down to show both the results of using the '10' punch (in) - '12' punch (out) and the '303' punch (in) if it exists to the '12' punch (out). In my final result I only want the '303' - '12' match if it exists or I will have duplicate records. All of this is being dumped in Report Builder 3.0 to calculate totals hours worked and dollars paid out per day ( no need for help there, just trying to give some context)
I have included the RowNumber in the final query results because I was thinking to use that to filter the results as needed. My thinking: if Count(RowNumber) = 2, return where RowNumber = '2', IF Count(RowNumber) = 1, return where RowNumber = '1', IF Count(RowNumber) = 4, return Where RowNumber = '3,4). In know the syntax in the phrasing here is wrong, but I am just using it to illustrate what I am trying to do. I am sure there is an easier way to write the query (though I am OK with if not) as long as I can figure out how to filter the results to only what I need. Any help is appreciated. Thanks!
Sample Data:
Timecard
| TimeCardID | StoreID | EmpID | CardDate
| PunchType | WorkCenter | BreakIndex |ShadowTimeCardForID
B6B839AD-D8DF-E611-A3E5-0019170149B6 | 32365 | 4171 |2017-01-21 07:54:00.500
| 303 | 4 |0 | 00000000-0000-0000-0000-000000000000
EmployeeRate
| EmployeeRateID | EmployeeID
| RateIndex | WorkCenter | OvertimeRate | RegularRate
| C3325A54-E7A9-E611-A16D-0019178089A7 | 27139B5C-7A74-E611-969E-3417EBD1A8D1
| 4 | 4 | 2250 |1500
Query:
DECLARE #datetime datetime = '2017-01-22 04:00:00.000'
SELECT
z.EmpID,
z.RegularRate,
z.OvertimeRate,
z.WorkCenter,
z.in_punch,
z.out_punch,
z.HoursWorked,
z.RowNumber
FROM
(SELECT
y.EmpID,
y.RegularRate,
y.OvertimeRate,
y.WorkCenter,
y.in_punch,
y.out_punch,
y.HoursWorked,
row_number() OVER(PARTITION BY EmpID ORDER BY EmpiD) AS RowNumber
FROM
(SELECT
f.EmpID,
f.RegularRate,
f.OvertimeRate,
f.WorkCenter,
f.in_punch,
f.out_punch,
f.HoursWorked
FROM
(SELECT
tc.EmpID,
er.RegularRate,
er.OvertimeRate,
tc.WorkCenter,
tc.in_punch,
tc.out_punch,
CONVERT(varchar(3),DATEDIFF(MINUTE,in_punch,out_punch)/60) + ':' +
RIGHT('0' + CONVERT(varchar(2),DATEDIFF(MINUTE,in_punch,out_punch)%60),2)
AS HoursWorked,
row_number() OVER(PARTITION BY tc.EmpID ORDER BY tc.EmpiD) AS RowNumber
FROM
(SELECT
e.EmpID,
e.WorkCenter,
e.CardDate AS in_punch,
e2.CardDate AS out_punch
FROM
(SELECT EmpID, CardDate, WorkCenter FROM TimeCard where PunchType = '10'
AND CardDate BETWEEN DATEADD(DAY, -1, #datetime) AND #datetime) e
INNER JOIN
(SELECT EmpID, CardDate, WorkCenter
FROM TimeCard where PunchType = '12' AND CardDate BETWEEN DATEADD(DAY, -1,
#datetime) AND #datetime) e2
ON
e.EmpID = e2.EmpID
) tc
INNER JOIN
[dbo].[Employee] em
ON tc.EmpID = em.EmpID
INNER JOIN
[dbo].[EmployeeRate] er
ON em.[EmployeeID] = er.[EmployeeID] AND tc.[Workcenter] = er.[WorkCenter]
WHERE tc.in_punch <= tc.out_punch
GROUP BY tc.EmpID,
er.RegularRate,
er.OvertimeRate,
tc.WorkCenter,
tc.in_punch,
tc.out_punch
) f
WHERE f.[RowNumber] <> '2'
UNION
SELECT
f.EmpID,
f.RegularRate,
f.OvertimeRate,
f.WorkCenter,
f.in_punch,
f.out_punch,
f.HoursWorked
FROM
(SELECT
tc.EmpID,
er.RegularRate,
er.OvertimeRate,
tc.WorkCenter,
tc.in_punch,
tc.out_punch,
CONVERT(varchar(3),DATEDIFF(MINUTE,in_punch,out_punch)/60) + ':' +
RIGHT('0' +
CONVERT(varchar(2),DATEDIFF(MINUTE,in_punch,out_punch)%60),2) AS
HoursWorked,
row_number() OVER(PARTITION BY tc.EmpID ORDER BY tc.EmpiD) AS RowNumber
FROM
(SELECT
e.EmpID,
e.WorkCenter,
e.CardDate AS in_punch,
e2.CardDate AS out_punch
FROM
(SELECT EmpID, CardDate, WorkCenter
FROM TimeCard where PunchType = '303' AND CardDate BETWEEN DATEADD(DAY, -1,
#datetime) AND #datetime) e
INNER JOIN
(SELECT EmpID, CardDate, WorkCenter
FROM TimeCard where PunchType = '12' AND CardDate BETWEEN DATEADD(DAY, -1,
#datetime) AND #datetime) e2
ON
e.EmpID = e2.EmpID
) tc
INNER JOIN
[dbo].[Employee] em
ON tc.EmpID = em.EmpID
INNER JOIN
[dbo].[EmployeeRate] er
ON em.[EmployeeID] = er.[EmployeeID] AND tc.[Workcenter] = er.[WorkCenter]
WHERE tc.in_punch <= tc.out_punch
GROUP BY tc.EmpID,
er.RegularRate,
er.OvertimeRate,
tc.WorkCenter,
tc.in_punch,
tc.out_punch
) f
WHERE f.[RowNumber] <> '2'
) y
) z
GROUP BY
z.EmpID,
z.RegularRate,
z.OvertimeRate,
z.WorkCenter,
z.in_punch,
z.out_punch,
z.HoursWorked,
z.RowNumber
ORDER BY COUNT(RowNumber)OVER(PARTITION BY EmpID)
Results:
EmpID,RegularRate,OvertimeRate,WorkCenter,in_punch,out_punch,HoursWorked,RowNumber
9267,1150,1725,9,2017-01-21 16:59:27.940,2017-01-22 01:16:16.200,8:17, 1
9438,550,825,3,2017-01-21 09:55:34.500,2017-01-21 15:37:51.770,5:42,1
9471,223,335,1,2017-01-21 10:32:08.060,2017-01-21 14:18:23.430,3:46,1
9471,223,335,1,2017-01-21 15:54:29.570,2017-01-21 23:00:00.000,7:06,2
4171,223,335,1,2017-01-21 07:54:00.490,2017-01-21 15:17:31.740,7:23,1
4171,1500,2250,4,2017-01-21 07:54:00.500,2017-01-21 15:17:31.740,7:23,2

Outputting 2 queries into one table (as extra columns)

I have 2 separate queries that i'd like to combine so that the results for both queries are output to 1 table
From the 2 queries below I'd like one table with the following columns:
StaffId, FullName, DayCount, MonthCount.
What is the best way of doing this?
SELECT TOP (10) COUNT(*) AS MonthCount, Staff.FirstName + Staff.LastName AS FullName, Staff.StaffID
FROM Sales INNER JOIN
Staff ON Sales.StaffID = Staff.StaffID LEFT OUTER JOIN
SaleEndorsements ON Sales.SaleID = SaleEndorsements.SaleID
WHERE Sales.CreationDate BETWEEN DATEADD(mm, DATEDIFF(mm,'',getdate()), '') AND getdate() AND SaleEndorsements.EndorsementID = 31
GROUP BY Staff.FirstName, Staff.LastName, Staff.StaffID
ORDER BY MonthCount DESC
SELECT TOP (10) COUNT(*) AS DayCount, Staff.FirstName + Staff.LastName AS FullName, Staff.StaffID
FROM Sales INNER JOIN
Staff ON Sales.StaffID = Staff.StaffID LEFT OUTER JOIN
SaleEndorsements ON Sales.SaleID = SaleEndorsements.SaleID
WHERE Sales.CreationDate BETWEEN DATEADD(DD, DATEDIFF(DD,'',getdate()), '') AND getdate() AND SaleEndorsements.EndorsementID = 31
GROUP BY Staff.FirstName, Staff.LastName, Staff.StaffID
ORDER BY DayCount DESC
Untested and so may be riddled with syntax errors but I think you need to do something like
Push the repeated functionality into a base CTE
Create another CTE with the month count referencing (1)
Create another CTE with the day count referencing (1)
Full Outer Join (2) and (3)
Additionally your WHERE clause makes the LEFT JOIN pointless so I've changed this to an INNER JOIN.
WITH T
AS (SELECT Staff.FirstName,
Staff.LastName,
Staff.StaffID,
Sales.CreationDate
FROM Sales
INNER JOIN Staff
ON Sales.StaffID = Staff.StaffID
INNER JOIN SaleEndorsements
ON Sales.SaleID = SaleEndorsements.SaleID
WHERE SaleEndorsements.EndorsementID = 31),
D
AS (SELECT TOP (10) COUNT(*) AS DayCount,
FirstName + LastName AS FullName,
StaffID
FROM T
WHERE CreationDate BETWEEN DATEADD(DD, DATEDIFF(DD, '', getdate()), '') AND
getdate()
GROUP BY FirstName,
LastName,
StaffID
ORDER BY DayCount DESC),
M
AS (SELECT TOP (10) COUNT(*) AS MonthCount,
FirstName + LastName AS FullName,
FROM T
WHERE CreationDate BETWEEN DATEADD(mm, DATEDIFF(mm, '', getdate()), '') AND
getdate()
GROUP BY FirstName,
LastName,
StaffID
ORDER BY MonthCount DESC)
SELECT ISNULL(M.StaffId, D.StaffId) AS StaffId,
ISNULL(M.FullName, D.FullName) AS FullName,
M.MonthCount,
D.DayCount
FROM M
FULL OUTER JOIN D
ON M.StaffID = D.StaffID
Add a UNION ALL clause to this, like so:
SELECT TOP (10) COUNT(*) AS MonthCount, Staff.FirstName + Staff.LastName AS FullName, Staff.StaffID FROM Sales INNER JOIN Staff ON Sales.StaffID = Staff.StaffID LEFT OUTER JOIN SaleEndorsements ON Sales.SaleID = SaleEndorsements.SaleID WHERE Sales.CreationDate BETWEEN DATEADD(mm, DATEDIFF(mm,'',getdate()), '') AND getdate() AND SaleEndorsements.EndorsementID = 31 GROUP BY Staff.FirstName, Staff.LastName, Staff.StaffID ORDER BY MonthCount DESC
union all
SELECT TOP (10) COUNT(*) AS DayCount, Staff.FirstName + Staff.LastName AS FullName, Staff.StaffID FROM Sales INNER JOIN Staff ON Sales.StaffID = Staff.StaffID LEFT OUTER JOIN SaleEndorsements ON Sales.SaleID = SaleEndorsements.SaleID WHERE Sales.CreationDate BETWEEN DATEADD(DD, DATEDIFF(DD,'',getdate()), '') AND getdate() AND SaleEndorsements.EndorsementID = 31 GROUP BY Staff.FirstName, Staff.LastName, Staff.StaffID ORDER BY DayCount DESC
If you can use a stored procedure, this would be a way of doing it:
CREATE PROCEDURE [dbo].[GetStats]
AS
SELECT TOP (10) Staff.StaffID, Staff.FirstName + Staff.LastName AS FullName, COUNT(*) AS MonthCount, 0 As DayCount
INTO #TempMonthlyStats
FROM Sales INNER JOIN
Staff ON Sales.StaffID = Staff.StaffID LEFT OUTER JOIN
SaleEndorsements ON Sales.SaleID = SaleEndorsements.SaleID
WHERE Sales.CreationDate BETWEEN DATEADD(mm, DATEDIFF(mm,'',getdate()), '') AND getdate() AND SaleEndorsements.EndorsementID = 31
GROUP BY Staff.FirstName, Staff.LastName, Staff.StaffID
ORDER BY MonthCount DESC
SELECT TOP (10) Staff.StaffID, Staff.FirstName + Staff.LastName AS FullName, 0 AS MonthCount, COUNT(*) As DayCount
INTO #TempDailyStats
FROM Sales INNER JOIN
Staff ON Sales.StaffID = Staff.StaffID LEFT OUTER JOIN
SaleEndorsements ON Sales.SaleID = SaleEndorsements.SaleID
WHERE Sales.CreationDate BETWEEN DATEADD(DD, DATEDIFF(DD,'',getdate()), '') AND getdate() AND SaleEndorsements.EndorsementID = 31
GROUP BY Staff.FirstName, Staff.LastName, Staff.StaffID
ORDER BY MonthCount DESC
SELECT #TempMonthlyStats.StaffID, #TempMonthlyStats.FullName, #TempMonthlyStats.MonthCount, COALESCE(#TempDailyStats.DayCount,0) AS DayCount
FROM #TempMonthlyStats
LEFT OUTER JOIN #TempDailyStats
ON #TempMonthlyStats.StaffID = #TempDailyStats.StaffID
ORDER BY MonthCount DESC

Cannot perform an aggregate function on a subquery

Can someone help me with this query?
SELECT p.OwnerName, SUM(ru.MonthlyRent) AS PotentinalRent, SUM(
(SELECT COUNT(t.ID) * ru.MonthlyRent FROM tblTenant t
WHERE t.UnitID = ru.ID)
) AS ExpectedRent
FROM tblRentalUnit ru
LEFT JOIN tblProperty p ON p.ID = ru.PropertyID
GROUP BY p.OwnerName
I'm having problems with the second sum, it won't let me do it. Evidently SUM won't work on subqueries, but I need to calculate the expected rent (MonthlyRent if there is a tenant assigned to the RentalUnit's id, 0 of they're not). How can I make this work?
SELECT p.OwnerName, SUM(ru.MonthlyRent) AS PotentialRent, SUM(cnt) AS ExpectedRent
FROM tblRentalUnit ru
LEFT JOIN
tblProperty p
ON p.ID = ru.PropertyID
OUTER APPLY
(
SELECT COUNT(t.id) * ru.MonthlyRent AS cnt
FROM tblTenant t
WHERE t.UnitID = ru.ID
) td
GROUP BY p.OwnerName
Here's a test script to check:
WITH tblRentalUnit AS
(
SELECT 1 AS id, 100 AS MonthlyRent, 1 AS PropertyID
UNION ALL
SELECT 2 AS id, 300 AS MonthlyRent, 2 AS PropertyID
),
tblProperty AS
(
SELECT 1 AS id, 'Owner 1' AS OwnerName
UNION ALL
SELECT 2 AS id, 'Owner 2' AS OwnerName
),
tblTenant AS
(
SELECT 1 AS id, 1 AS UnitID
UNION ALL
SELECT 2 AS id, 1 AS UnitID
)
SELECT p.OwnerName, SUM(ru.MonthlyRent) AS PotentialRent, SUM(cnt) AS ExpectedRent
FROM tblRentalUnit ru
LEFT JOIN
tblProperty p
ON p.ID = ru.PropertyID
OUTER APPLY
(
SELECT COUNT(t.id) * ru.MonthlyRent AS cnt
FROM tblTenant t
WHERE t.UnitID = ru.ID
) td
GROUP BY p.OwnerName
What is the meaning of the sum of the unitMonthlyRent times the number of tenants, for some partiicular rental unit (COUNT(t.ID) * ru.MonthlyRent )?
Is it the case that all you are trying to do is see the difference between the total potential rent from all untis versus the expected rent (From only occcupied units) ? If so, then try this
Select p.OwnerName,
Sum(r.MonthlyRent) AS PotentinalRent,
Sum(Case t.Id When Null Then 0
Else r.MonthlyRent End) ExpectedRent
From tblRentalUnit r
Left Join tblTenant t
On t.UnitID = r.ID
left Join tblProperty p
On p.ID = r.PropertyID)
Group By p.OwnerName