I am running the below query in sql but it is giving the below error.
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
What I have tried :
SELECT b.Service_Name,
c.Service_Type,
Application_No,
Reg_No,
Student_Name,
(SELECT CONVERT(char(10),
dt + (SELECT COUNT(1)
FROM Holiday_list
WHERE Date_Fmt BETWEEN School_update AND dt),
103) AS cnt
FROM (SELECT CASE WHEN Service_TypeID = '1' THEN (School_update + 30) ELSE (School_update + 5) END AS dt
FROM Application_Status) a ) AS Nxt_date,
DATEDIFF(DAY, School_update, GETDATE()) AS Day_Count,
Created_Date,
School_Code,
CASE WHEN Payment_Status = 'Y' THEN 'PAID' WHEN Payment_Status = 'N' THEN 'NOT PAID' END AS Payment_Status
FROM Application_Status a,
MST_Service b,
MST_ServiceType c,
KSEEBMASTERS.dbo.MST_SCHOOL s,
MST_Division d
WHERE a.Service_ID = b.Service_ID
AND s.SCM_SCHOOL_CODE COLLATE Latin1_General_CI_AI = a.School_Code
AND s.DIST_CODE COLLATE Latin1_General_CI_AI = d.DistrictCode
AND a.Service_TypeID = c.Type_ID
AND d.DivisionCode = 'ED'
AND Payment_Status = 'Y'
AND school_status = 'Y'
AND Div_Status = 'N';
But the problem is in the below query while joining the query to another query.
SELECT CONVERT(char(10),
dt + (SELECT COUNT(*)
FROM Holiday_list
WHERE Date_Fmt BETWEEN School_update AND dt),
103) AS cnt
FROM (SELECT CASE WHEN Service_TypeID = '1' THEN (School_update + 30) ELSE (School_update + 5) END AS dt,
School_update
FROM Application_Status) a;
Here Application_Status is sone table with Column name School_Update and Holiday_List is another table with column name Date_Fmt.
The answer is in the error message: if you nest a query to get a field, that query must return one and only one row.
So your issue is there in the last query that you posted, but not in nested query SELECT COUNT(*) FROM Holiday_list (...) because it's an aggregate query.
Maybe it's just that SELECT CASE WHEN Service_TypeID = '1' THEN (School_update + 30) ELSE (School_update + 5) END AS dt, School_update FROM Application_Status returns more then one row and therefore also the query that contains it.
Related
I am getting an error near Alias Names i.e., Month_Name, Limit_Mins, Amount in this dynamic sql, how do i resolve that , i tried with adding one more quote, but when i do tyhat i am only getting #columnames into the sql. How do i resolve the error and make it part of the string
DECLARE #columns NVARCHAR(MAX) = '', #sql NVARCHAR(MAX) = '';
SELECT
#columns = coalesce(#columns + ',', '') + quotename(Limit_Mins)
from
(
select DISTINCT
(L.Limit_Mins ) as 'Limit_Mins'
from
Limit L
)
AS lIMITS
SELECT #columns
SET
#sql = 'select * from (
SELECT
month (Sa.[Date]) AS 'Month_Name',
convert(varchar(10),
case
when
S.Limit_Mins = L.Limit_Mins
and S.Childcare_Flag = 1
then
S.Limit_Mins
else
0
end
) as 'Limit_Mins', sum(
case
when
S.Childcare_Flag = 1
and S.Limit_Mins = L.Limit_Mins
then
case
when
D.PID = Sa.PID
and D.Discount_Date = Sa.[Date]
then
D.Discount_Price
else
P.Retail_price
end
*Sa.Quantity
else
0
end
) as 'Amount'
FROM
Limit L
join
Store S
on L.Limit_Mins = S.Limit_Mins
join
Sale Sa
on S.Store_Number = Sa.Store_number
join
[Date] Dt
on Dt.[Date] = Sa.[Date]
join
Product P
on Sa.PID = P.PID
left outer join
Discount D
on Sa.PID = D.PID
and Sa.[Date] = D.Discount_Date
WHERE
Sa.[Date] >= DATEADD(year, - 1, DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1))
AND Sa.[Date] < DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1) -- DATEDIFF(MM,Sale.[Date] ,GETDATE())<=12
--and Sale.[Date] < DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
GROUP BY
month(Sa.[Date]) ,
case
when
S.Limit_Mins = L.Limit_Mins
and S.Childcare_Flag = 1
then
S.Limit_Mins
else
0
end
union all
SELECT
month (Sa.[Date]) AS 'Month_Name',
''No Childcare'' as 'Limit_Mins',
isnull(sum(
case
when
S.Childcare_Flag = 0
then
case
when
D.PID = Sa.PID
and D.Discount_Date = Sa.[Date]
then
D.Discount_Price
else
P.Retail_price
end
*Sa.Quantity
else
0
end
), 0) as 'Sales_Amount'
FROM
Store S
join
Sale Sa
on S.Store_Number = Sa.Store_number
join
[Date] Dt
on Dt.[Date] = Sa.[Date]
join
Product P
on Sa.PID = P.PID
left outer join
Discount D
on Sa.PID = D.PID
and Sa.[Date] = D.Discount_Date
WHERE
Sa.[Date] >= DATEADD(year, - 1, DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1))
AND Sa.[Date] < DATEFROMPARTS(YEAR(GETDATE()), MONTH(GETDATE()), 1) -- DATEDIFF(MM,Sale.[Date] ,GETDATE())<=12
--and Sale.[Date] < DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
GROUP BY
month(Sa.[Date])
)
A PIVOT(sum(Amount) for Limit_Mins in
(
'+#columns+
',[No Childcare]
)
)as PIVOTTable
order by
[Month]'
print #sql
Use brackets instead of quotes: month (Sa.[Date]) AS [Month_Name],
I tried the quotes earlier, but it was throwing an error invalid column which i later realized was happening because i renamed the alias and forgot to rename the same column order by , Thanks for the input
I am trying to use MAX() to select the most recent placement date within our database, and use Table_CTE so I can then select and filter between the dates desired.
BEGIN
DECLARE #Rangetill DATE, #Rangefrom DATE
SET #rangefrom = DATEADD(day, -50, GETDATE())
SET #Rangetill = DATEADD(day, -90, GETDATE());
WITH Table_CTE (Name, ID, Rangefrom, Rangetill, StatusID, Statusdate) AS
(
SELECT
PE.Personname + ' ' + PE.Surname [Name],
A.ApplicantId,
#rangefrom [Expiry warning from],
#rangetill [Expiry warning till],
A.Statusid,
selected = CASE
WHEN P.EndDate IS NOT NULL AND P.EndDate > A.StatusDate
THEN CONVERT(DATE, P.EndDate, 103)
ELSE CONVERT(DATE, A.StatusDate, 103)
END
FROM
Applicants AS A
LEFT JOIN
Person AS PE ON A.ApplicantId = PE.PersonID
LEFT JOIN
Placements AS P on A.applicantid = P.Applicantid
)
SELECT *
FROM Table_CTE
WHERE table_cte.Statusdate BETWEEN #Rangetill AND #Rangefrom
AND (Table_CTE.StatusID = 58 OR Table_CTE.statusid = 63)
ORDER BY Name DESC
END
The above selects the right information but also selects duplicate applicants with placement end dates (p.enddate) as they could have been placed more than once. The WHERE clause also limits the most recent enddate to within the range provided by the Variables and as there needs to be a log there will be multiple end dates. so my solution or idea would be to uses a max() within the Case or CTE Select. However I am not sure how to use or work with Max() in this case.
In this case I would like to check and return the Max(p.enddate) if it exists and store that in the statusdate of Table_CTE.
Is this possible and is it the best way to provide this information in a stored procedure?
In the CTE would be more efficient but this is easier
SELECT c.[Name], max(c.Statusdate)
FROM Table_CTE c
WHERE c.Statusdate Between #Rangetill and #Rangefrom
AND c.StatusID in (58, 63)
group by c.[Name]
Add the other columns on your own
Declare
#Rangetill date,
#Rangefrom date
SET #rangefrom = DATEADD(day, -50, GETDATE())
SET #Rangetill = DATEADD(day, -90, GETDATE());
With Table_CTE ( ID, Rangefrom, Rangetill, Statusdate)
AS (
Select
A.ApplicantId
, #rangefrom [Expiry warning from]
, #rangetill [Expiry warning till]
, selected = CASE
WHEN max(P.EndDate) IS NOT NULL AND max(P.EndDate) > max(A.StatusDate)
THEN max(CONVERT(DATE, P.EndDate, 103))
ELSE max(CONVERT(DATE, A.StatusDate, 103))
END
FROM Applicants AS A
LEFT JOIN Person AS PE ON A.ApplicantId = PE.PersonID
LEFT JOIN Placements AS P on A.applicantid = P.Applicantid
GROUP BY A.ApplicantId
)
SELECT
PE.PersonName + ' ' + PE.Surname [NAME]
, A.ApplicantId
, Table_CTE.ID
, Table_CTE.Statusdate
, #Rangefrom [Range from]
, #Rangetill [Range till]
FROM Table_CTE
LEFT JOIN Applicants AS A ON A.ApplicantId = Table_CTE.ID
LEFT JOIN Person as PE on PE.PersonID = A.ApplicantId
WHERE table_cte.Statusdate Between #Rangetill and #Rangefrom
AND (A.StatusID = 58 or A.statusid = 63 )
Order by PE.PersonName + ' '+ PE.Surname desc
END
Really messy way around things but I got my solution by removing all but the variables and ID from CTE so I could select Max(DATE) on both A.statusdate and P.EndDate.
By doing this I could group by A.ApplicantID and rejoin specific tables outside of the CTE in order to get Applicant Name and Status ID back into my results set.
Thank you for your help everyone.
I have quite a long SELECT query but I have pasted the relevant part here.
I need to use the result of the of my CASE statement to use in another CASE statement. I'm doing this in SQL Server.
Would be very grateful for help.
SELECT
CompanyContact.Name AS CompanyName,
CASE
WHEN SUBSTRING(HeadLease.TenantBreakNotice, LEN(HeadLease.TenantBreakNotice), 1) = 'M'
THEN CONVERT(VARCHAR(10), DATEADD(DD, -365 / (12 / SUBSTRING(HeadLease.TenantBreakNotice, 1, LEN(HeadLease.TenantBreakNotice) - 1)), HeadLease.TenantBreakDate), 103)
WHEN SUBSTRING(HeadLease.TenantBreakNotice, LEN(HeadLease.TenantBreakNotice), 1) = 'Y'
THEN CONVERT(VARCHAR(10), DATEADD(DD, -365 * (SUBSTRING(HeadLease.TenantBreakNotice, 1, LEN(HeadLease.TenantBreakNotice) - 1)), HeadLease.TenantBreakDate), 103)
ELSE HeadLease.TenantBreakNotice
END AS [TenantBreakNotice], <-- I need this to be used in the case statement below.
CASE
WHEN [TenantBreakNotice] < CONVERT(varchar(10), getdate(), 103)
THEN 'Expiry'
WHEN [TenantBreakNotice] IS NULL
THEN 'Expiry'
ELSE 'Break'
END AS [LeaseEventType]
FROM
HeadLease
You cannot use a column alias in the same select where it is defined. The usual solution is to repeat the logic (hard to maintain), use a subquery, or CTE. SQL Server offers another elegant solution:
SELECT hl.Name AS CompanyName, v.TenantBreakNotice,
(CASE WHEN v.TenantBreakNotice < CONVERT(varchar(10), getdate(), 103) THEN 'Expiry'
WHEN TenantBreakNotice IS NULL THEN 'Expiry'
ELSE 'Break'
END) AS [LeaseEventType]
FROM HeadLease hl OUTER APPLY
(VALUES (CASE WHEN SUBSTRING(hl.TenantBreakNotice, LEN(hl.TenantBreakNotice), 1) = 'M'
THEN CONVERT(VARCHAR(10), DATEADD(DAY, -365/(12/SUBSTRING(hl.TenantBreakNotice, 1, LEN(hl.TenantBreakNotice) -1)), hl.TenantBreakDate), 103)
WHEN SUBSTRING(hl.TenantBreakNotice, LEN(hl.TenantBreakNotice), 1) = 'Y'
THEN CONVERT(VARCHAR(10), DATEADD(DAY, -365*(SUBSTRING(hl.TenantBreakNotice,1, LEN(hl.TenantBreakNotice)-1)), hl.TenantBreakDate), 103)
ELSE hl.TenantBreakNotice
END) v(TenantBreakNotice);
Of course, the logic is incorrect, because you are comparing dates as strings. However, that is something you need to figure out yourself. Don't convert dates to strings for date operations. And, you should output the results as YYYY-MM-DD so the formats are unambiguous.
As #Juergen pointed out, you can't do exactly what you want, but you could compute the first CASE expression in a subquery, and then use it an outer wrapping query:
WITH cte AS (
SELECT
Name AS CompanyName,
CASE WHEN SUBSTRING(HeadLease.TenantBreakNotice,LEN(HeadLease.TenantBreakNotice), 1) = 'M'
THEN CONVERT(VARCHAR(10), DATEADD(DD,-365/(12/SUBSTRING(HeadLease.TenantBreakNotice,1,LEN(HeadLease.TenantBreakNotice)-1)),HeadLease.TenantBreakDate), 103)
WHEN SUBSTRING(HeadLease.TenantBreakNotice,LEN(HeadLease.TenantBreakNotice),1) = 'Y'
THEN CONVERT(VARCHAR(10), DATEADD(DD,-365*(SUBSTRING(HeadLease.TenantBreakNotice,1,LEN(HeadLease.TenantBreakNotice)-1)),HeadLease.TenantBreakDate), 103)
ELSE HeadLease.TenantBreakNotice
END AS [TenantBreakNotice]
FROM HeadLease
)
SELECT
Name,
TenantBreakNotice,
CASE WHEN TenantBreakNotice < CONVERT(varchar(10), getdate(), 103)
THEN 'Expiry'
WHEN TenantBreakNotice IS NULL THEN 'Expiry'
ELSE 'Break'
END AS [LeaseEventType]
FROM cte;
Use CTEs (common table expressions). In CTEs you can refer to the columns from the previous CTE, so you can split the CASE logic like you would like.
Example:
WITH
CTE_1 AS
(
SELECT
*
,CASE
WHEN SUBSTRING(HeadLease.TenantBreakNotice,LEN(HeadLease.TenantBreakNotice),1) = 'M'
THEN CONVERT(VARCHAR(10), DATEADD(DD,-365/(12/SUBSTRING(HeadLease.TenantBreakNotice,1,LEN(HeadLease.TenantBreakNotice)-1)),HeadLease.TenantBreakDate), 103)
WHEN SUBSTRING(HeadLease.TenantBreakNotice,LEN(HeadLease.TenantBreakNotice),1) = 'Y'
THEN CONVERT(VARCHAR(10), DATEADD(DD,-365*(SUBSTRING(HeadLease.TenantBreakNotice,1,LEN(HeadLease.TenantBreakNotice)-1)),HeadLease.TenantBreakDate), 103)
ELSE
HeadLease.TenantBreakNotice
END AS [TenantBreakNotice]
...
),
CTE_2 AS
(
SELECT
*
,CASE
WHEN [TenantBreakNotice] < CONVERT(varchar(10),getdate(),103) THEN 'Expiry'
WHEN [TenantBreakNotice] IS NULL THEN 'Expiry'
ELSE 'Break'
END AS [LeaseEventType]
FROM
CTE_1
)
SELECT * FROM CTE_2
You can move the first case expression into your from by using a derived table/subquery like so:
select
cc.Name as CompanyName
, convert(varchar(10),hl.[TenantBreakNotice],103) as TenantBreakNotice
, case
when hl.[TenantBreakNotice] < getdate() then 'Expiry'
when hl.[TenantBreakNotice] is null then 'Expiry'
else 'Break'
end as [LeaseEventType]
from (
select *,
case
when substring(HeadLease.TenantBreakNotice,len(HeadLease.TenantBreakNotice),1) = 'M'
then dateadd(day,-365/(12/substring(HeadLease.TenantBreakNotice,1,len(HeadLease.TenantBreakNotice)-1)),HeadLease.TenantBreakDate)
when substring(HeadLease.TenantBreakNotice,len(HeadLease.TenantBreakNotice),1) = 'Y'
then dateadd(day,-365*(substring(HeadLease.TenantBreakNotice,1,len(HeadLease.TenantBreakNotice)-1)),HeadLease.TenantBreakDate)
else HeadLease.TenantBreakNotice
end as [TenantBreakNotice]
from HeadLease
) as hl
inner join CompanyContact cc
on cc....
Notes:
Don't compare strings as dates, this is going to lead to problems; especially with the style you specified (103).
Bad Habits to Kick : Using shorthand with date/time operations - Aaron Bertrand
Bad habits to kick : mis-handling date / range queries - Aaron Bertrand
I have two queries. One query pulls the information based on the orders that have been scheduled to them in a day by employee. The other query pulls the number of orders that have been completed and paid in a day, along with the total amount of the revenue from the orders.
I have scraped the forums to get the code together to get these queries, but I need to have both queries joined together. I want to use this information in report builder once I get it done. It's probably simple for someone, but it's confusing me as I'm far from any sort of expert with SQL.
I only need one day at the moment, but found this code and modified for now and hope that I can use it in the future when needing week and month data.
Any help would be appreciated.
Query 1
declare #dt DATE = '20160823'
set DATEFIRST 7;
set #dt = dateadd(week, datediff(week, '19050101', #dt), '19050101');
;with dt as
(
select
Technician = (CASE emp_id
WHEN 'CW697' THEN 'Joe Biggs'
WHEN 'DZ663' THEN 'Mimi Cassidy'
END),
dw = datepart(weekday, DATE)
from
dbo.ordemps
where
date >= #dt and date <dateadd(day, 7, #dt)
),
x AS
(
select
Technician, dw = coalesce(dw,8),
c = convert(varchar(11), COUNT(*))
from
dt
group by
grouping sets((Technician), (Technician,dw))
)
select
Technician,
[Sun] = coalesce([1], '-'),
[Mon] = coalesce([2], '-'),
[Tue] = coalesce([3], '-'),
[Wed] = coalesce([4], '-'),
[Thu] = coalesce([5], '-'),
[Fri] = coalesce([6], '-'),
[Sat] = coalesce([7], '-'),
TOTAL =[8]
from
x
PIVOT
(MAX(c) FOR dw IN([1],[2],[3],[4],[5],[6],[7],[8])) as pvt;
Query 2
select
case
when grouping(d.m)=15 then 'Year ' + cast(max(d.y) as varchar(10))
when grouping(date)=15 then datename(m, max(DATE)) + ' ' + cast(max(d.y) as varchar(10))
else cast(cast([date] as date) as varchar(255))
end as DATE,
TotalOrders = /*sum(Amount)*/convert(varchar(11), COUNT(*)),
TotalSales = sum(Amount),
Technician = (CASE recv_by
WHEN 'CW697' THEN 'Joe Biggs'
WHEN 'DZ663' THEN 'Mimi Cassidy'
END)
from
ordpay
cross apply
(select
datepart(yy, [date]),
datepart(m, [date])
) d(y, m)
where
[DATE] >= dateadd(day, datediff(day, 1, getdate()), 0)
and [date] < dateadd(day, datediff(day, 0, getdate()), 0)
group by
recv_by, d.y, rollup (d.m, date)
order by
d.y desc, grouping(d.m), d.m, grouping(DATE), DATE
At the easiest level you can use can join sub-queries. Your example is a little trickier because you are using CTEs which can't go in the subquery. To get you going in the right direction it should generally look like this:
with cte1 as (),
cte2 as ()
select *
from (
select *
from tables
where criteria -- subquery 1 (cannot contain order by)
) a
join ( -- could be a left join
select *
from tables
where criteria -- subquery 2 (cannot contain order by)
) b
on b.x = a.x --join criteria
where --additional criteria
order by --final sort
where subquery 1 would be your query 1 from select Technician to the end
and subquery 2 would be everything from your query 2 except the order by.
For further information on joins see the MSDN documentation
Since you aren't going to research much it doesn't seem here's a clunky and quick way, and keeps it simple for you, without having to explain a lot if we were to join the queries together more elegantly.
The first set of code has 2 common table expressions (CTE). So, select those results into a temp. Notice the --addition here
....
select
Technician,
[Sun] = coalesce([1], '-'),
[Mon] = coalesce([2], '-'),
[Tue] = coalesce([3], '-'),
[Wed] = coalesce([4], '-'),
[Thu] = coalesce([5], '-'),
[Fri] = coalesce([6], '-'),
[Sat] = coalesce([7], '-'),
TOTAL =[8]
into #someTemp --Addition here
from
....
Do the same for your second query...
...
into #someOtherTemp --Addition here
from
ordpay
...
Then join them togehter...
select t1.someColumns, t2.someOtherColumns
from #someTemp t1
inner join #someOtherTemp t2 on t1.column = t2.column
How do I show the missing days in the query below which uses a join on a calendar table in SQL Server 2012?
The values for the missing day should be 0.
;WITH g AS
(
SELECT calendar.year, calendar.month, calendar.day, calendar.MonthName,
CAST(calendar.day AS NVARCHAR(2)) + '.' + CAST(calendar.month AS NVARCHAR(2)) + '.' + CAST(calendar.year AS NVARCHAR(16))AS DayMonthAndYear,
calendar.MonthName + ' ' + CAST(calendar.year AS NVARCHAR(16)) AS MonthNameAndYear,
COUNT(profileviews.ID) AS total_profileviews
FROM core_Calendar AS calendar
LEFT JOIN members_ProfileViews AS profileviews
ON CONVERT(DATE, calendar.date) = CONVERT(DATE, profileviews.CreatedAt)
WHERE calendar.date >= CONVERT(DATE, '03.02.2015')
AND calendar.date <= CONVERT(DATE, '03.02.2016')
AND profileviews.MemberID = 10
GROUP BY calendar.year, calendar.month, calendar.day, calendar.MonthName
)
SELECT g.year, g.month, g.day, g.MonthName, g.DayMonthAndYear, g.MonthNameAndYear, total_profileviews,
SUM(g.total_profileviews) OVER (ORDER BY g.year,g.month,g.day ROWS UNBOUNDED PRECEDING) AS rt_profileviews
FROM g
ORDER BY g.year, g.month, g.day;
You need to move the profileviews.MemberID = 10 to the LEFT JOIN, since it's essentially converting it to an INNER JOIN:
WITH g AS
(
SELECT C.[year],
C.[month],
C.[day],
C.[MonthName],
CONVERT(VARCHAR(10),C.[date],104) AS DayMonthAndYear,
C.[MonthName] + ' ' + CAST(C.[year] AS NVARCHAR(16)) AS MonthNameAndYear,
COUNT(profileviews.ID) AS total_profileviews
FROM core_Calendar AS C
LEFT JOIN ( SELECT *
FROM members_ProfileViews
WHERE MemberID = 10) AS P
ON CONVERT(DATE, C.[date]) = CONVERT(DATE, P.CreatedAt)
WHERE C.[date] >= CONVERT(DATE, '03.02.2015',104)
AND C.[date] <= CONVERT(DATE, '03.02.2016',104)
GROUP BY C.[year], C.[month], C.[day], C.[MonthName]
)
SELECT g.[year],
g.[month],
g.[day],
g.[MonthName],
g.DayMonthAndYear,
g.MonthNameAndYear,
total_profileviews,
SUM(g.total_profileviews) OVER (ORDER BY g.[year],g.[month],g.[day] ROWS UNBOUNDED PRECEDING) AS rt_profileviews
FROM g
ORDER BY g.[year], g.[month], g.[day];