Pivot with Dynamic sql as Parameter - sql-server

I am not sure if this is the way to go though but I would like to know if there is someway to have a stored procedure and pass in a queries to get the values to pivot. I'm not sure if this is a good idea, so sorry if this is a stupid question, but it would be great to pass in a query instead of hard coding every single pivot you want. I have an example of the pivot Stored Procedure that I have coded. This also includes the grand totals for rows and columns.
Don't know if I should add the code as well?
Hope this makes sense.
Please see my stored procedure code below:
CREATE PROCEDURE [dbo].[PivotNoAgentPerc_SP]
AS
DECLARE #columnHeaders VARCHAR (MAX)
SELECT #columnHeaders = COALESCE(#columnHeaders + ', ','')+ QUOTENAME(granteddate)
FROM
(
SELECT DISTINCT EOMONTH(BondSales.granteddate,0) AS granteddate
FROM ccbsm_ccbsm_salemanagement AS BondSales
LEFT OUTER JOIN ccbsm_ccbsm_salemanagement_cstm AS BondSalesCSTM ON BondSales.id = BondSalesCSTM.id_c
LEFT OUTER JOIN CapcubedInternalDB.dbo.ProvincialArea AS ProvincialArea ON BondSalesCstm.provincial_level_c = ProvincialArea.ID
LEFT OUTER JOIN accounts AS accounts_1 ON BondSales.account_id1_c = accounts_1.id AND accounts_1.deleted = 0
LEFT OUTER JOIN users AS ConsultantUser ON BondSales.Assigned_user_id = ConsultantUser.id AND ConsultantUser.deleted = 0
LEFT OUTER JOIN CapcubedInternalDB.dbo.BondSaleApplicationStatus AS BondSalesStatus ON BondSalesStatus.ID = BondSales.applicationstatus
WHERE BondSales.deleted = 0
AND ProvincialArea.SAD_Province = 'Coastal'
AND BondSalesStatus.AuditedStatus = 1
AND EOMONTH(BondSales.granteddate,0) BETWEEN EOMONTH(GETDATE(),-12) AND EOMONTH(GETDATE(),-1)
) AS B
ORDER BY B.granteddate
/* GRAND TOTAL COLUMN */
DECLARE #GrandTotalCol NVARCHAR (MAX)
SELECT #GrandTotalCol =
COALESCE (#GrandTotalCol + 'ISNULL ([' + CAST (granteddate AS VARCHAR) +'],0) + ', 'ISNULL([' + CAST(granteddate AS VARCHAR)+ '],0) + ')
FROM
(
SELECT DISTINCT EOMONTH(BondSales.granteddate,0) AS granteddate
FROM ccbsm_ccbsm_salemanagement AS BondSales
LEFT OUTER JOIN ccbsm_ccbsm_salemanagement_cstm AS BondSalesCSTM ON BondSales.id = BondSalesCSTM.id_c
LEFT OUTER JOIN CapcubedInternalDB.dbo.ProvincialArea AS ProvincialArea ON BondSalesCstm.provincial_level_c = ProvincialArea.ID
LEFT OUTER JOIN accounts AS accounts_1 ON BondSales.account_id1_c = accounts_1.id AND accounts_1.deleted = 0
LEFT OUTER JOIN users AS ConsultantUser ON BondSales.Assigned_user_id = ConsultantUser.id AND ConsultantUser.deleted = 0
LEFT OUTER JOIN CapcubedInternalDB.dbo.BondSaleApplicationStatus AS BondSalesStatus ON BondSalesStatus.ID = BondSales.applicationstatus
WHERE BondSales.deleted = 0
AND ProvincialArea.SAD_Province = 'Coastal'
AND BondSalesStatus.AuditedStatus = 1
AND EOMONTH(BondSales.granteddate,0) BETWEEN EOMONTH(GETDATE(),-12) AND EOMONTH(GETDATE(),-1)
) AS B
ORDER BY B.granteddate
SET #GrandTotalCol = LEFT (#GrandTotalCol, LEN (#GrandTotalCol)-1)
/* GRAND TOTAL ROW */
DECLARE #GrandTotalRow NVARCHAR(MAX)
SELECT #GrandTotalRow =
COALESCE(#GrandTotalRow + ',ISNULL(SUM([' + CAST(granteddate AS VARCHAR)+']),0)', 'ISNULL(SUM([' + CAST(granteddate AS VARCHAR)+']),0)')
FROM
(
SELECT DISTINCT EOMONTH(BondSales.granteddate,0) AS granteddate
FROM ccbsm_ccbsm_salemanagement AS BondSales
LEFT OUTER JOIN ccbsm_ccbsm_salemanagement_cstm AS BondSalesCSTM ON BondSales.id = BondSalesCSTM.id_c
LEFT OUTER JOIN CapcubedInternalDB.dbo.ProvincialArea AS ProvincialArea ON BondSalesCstm.provincial_level_c = ProvincialArea.ID
LEFT OUTER JOIN accounts AS accounts_1 ON BondSales.account_id1_c = accounts_1.id AND accounts_1.deleted = 0
LEFT OUTER JOIN users AS ConsultantUser ON BondSales.Assigned_user_id = ConsultantUser.id AND ConsultantUser.deleted = 0
LEFT OUTER JOIN CapcubedInternalDB.dbo.BondSaleApplicationStatus AS BondSalesStatus ON BondSalesStatus.ID = BondSales.applicationstatus
WHERE BondSales.deleted = 0
AND ProvincialArea.SAD_Province = 'Coastal'
AND BondSalesStatus.AuditedStatus = 1
AND EOMONTH(BondSales.granteddate,0) BETWEEN EOMONTH(GETDATE(),-12) AND EOMONTH(GETDATE(),-1)
)AS B
ORDER BY B.granteddate
/* MAIN QUERY */
DECLARE #FinalQuery NVARCHAR (MAX)
SET #FinalQuery = 'SELECT *, ('+ #GrandTotalCol + ')
AS [Grand Total] INTO #temp_MatchesTotal
FROM
(SELECT
ISNULL(ConsultantUser.user_name,''Total'') AS [Consultant],
EOMONTH(BondSales.granteddate,0) AS [Month Granted],
COALESCE(CAST(CAST(SUM(CASE WHEN accounts_1.name = ''No Agent Channel'' THEN 1 ELSE 0 END) AS DECIMAL)/COUNT(BondSales.name) AS decimal(5,2)), 0) AS NoAgentPerc
FROM ccbsm_ccbsm_salemanagement AS BondSales
LEFT OUTER JOIN ccbsm_ccbsm_salemanagement_cstm AS BondSalesCSTM ON BondSales.id = BondSalesCSTM.id_c
LEFT OUTER JOIN CapcubedInternalDB.dbo.ProvincialArea AS ProvincialArea ON BondSalesCstm.provincial_level_c = ProvincialArea.ID
LEFT OUTER JOIN accounts AS accounts_1 ON BondSales.account_id1_c = accounts_1.id AND accounts_1.deleted = 0
LEFT OUTER JOIN users AS ConsultantUser ON BondSales.Assigned_user_id = ConsultantUser.id AND ConsultantUser.deleted = 0
LEFT OUTER JOIN CapcubedInternalDB.dbo.BondSaleApplicationStatus AS BondSalesStatus ON BondSalesStatus.ID = BondSales.applicationstatus
WHERE BondSales.deleted = 0
AND ProvincialArea.SAD_Province = ''Coastal''
AND BondSalesStatus.AuditedStatus = 1
AND EOMONTH(BondSales.granteddate,0) BETWEEN EOMONTH(GETDATE(),-12) AND EOMONTH(GETDATE(),-1)
GROUP BY EOMONTH(BondSales.granteddate, 0), ConsultantUser.user_name
) A
PIVOT
(
SUM(NoAgentPerc)
FOR [Month Granted]
IN ('+#columnHeaders +')
) B
ORDER BY [Consultant]
SELECT * FROM #temp_MatchesTotal
UNION ALL
SELECT ''Grand Total'','+ #GrandTotalRow +', ISNULL (SUM([Grand Total]),0)
FROM #temp_MatchesTotal
DROP TABLE #temp_MatchesTotal'
EXECUTE(#FinalQuery)
Sorry if the code is long but I just wanted to show you exactly what I an talking about

I have done this is in procedure and it is working fine. Compare your example to below code
You have to write Dynamic sql query
Example :
declare #s date
declare #e date
declare #dates varchar(MAX)
set #s=DATEADD(DAY,-1,#startdate)
set #e=#enddate
IF OBJECT_ID('tempdb.#DATES') IS NOT NULL
DROP TABLE #DATES
CREATE TABLE #DATES
(
ID INT PRIMARY KEY IDENTITY(1,1),
Date VARCHAR(MAX)
)
WHILE (#s<#e)
BEGIN
INSERT INTO #DATES (Date)
select CONCAT( '[',DATEADD(DAY ,1, #s),']')
set #s=DATEADD(DAY ,1, #s)
END
SELECT #dates= STUFF((
SELECT ',' + SPACE(1) + Date
FROM #DATES
FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '')
--AS [Dates]
------------------------Getting RDW Datewise--------------------------------------
declare #queryRDW VARCHAR(MAX)
set #queryRDW='
select * from (
SELECT SUM(RecordValue)/60 RecordValue,RecordType ,Computationdate ,t2.ProjectResourceId,t1.ResourceCode,t1.ResourceName
FROM tblProjectResource t1 INNER JOIN tblDeploymentWorkbook t2 on t1.ProjectResourceId=t2.ProjectResourceId
WHERE
RecordType=''RDW'' and t2.SubCategoryId IN (1)
GROUP BY
RecordType, Computationdate,t2.ProjectResourceId,t1.resourceCode,t1.ResourceName
HAVING
Computationdate >= '''+Cast(#startdate as varchar)+''' and Computationdate <= '''+Cast(#enddate as varchar)+'''
)tab
PIVOT(
SUM(RecordValue) for ComputationDate in ( '+#dates+')
)t
Order By ResourceName
'
exec (#queryRDW)

Related

Using DECLARE while creating a VIEW?

The literature says that the declare statement is not compatible with creating a View. How do I get around it?
My declare statement looks like:
DECLARE #risk_5 TABLE (Code VARCHAR(100));
INSERT INTO #risk_5 (Code) VALUES ('AA'),('BB'),('CC');
and is then used within a select statement:
SELECT
id,
CASE
WHEN a.[10_2_1_Country] IN (SELECT Code from #risk_5)
THEN '3'
END AS Risk_Country5
FROM x
The recommendation is to pack the declare into a CTE or a stored procedure.
With both these recommendations though, I do not understand how to connect the two? What am I missing?
If you need to use variable try to use stored procedures, if you write a select query in the stored procedure you can get the data too. And you can use declare inside.
I use this way in my solution e.g.
CREATE PROCEDURE [dbo].[GetLoadSiteMass]( #month INT,
#year int,
#storageId int,
#parent nvarchar(50),
#materialSourceId nvarchar(100),
#complexIds nvarchar(50))
AS
BEGIN
DECLARE #MonthPrev int
DECLARE #YearPrev int
SET #MonthPrev = CASE WHEN #Month = 1 THEN 12 ELSE #Month - 1 END
SET #YearPrev = CASE WHEN #Month = 1 THEN #Year - 1 ELSE #Year END
declare #WagonLoadSiteId int
set #WagonLoadSiteId = (select top 1 CarriageLoadSiteId from CarriageLoadSite where LoadSiteType = 2);
DECLARE #loadSide nvarchar(10), #result decimal(18,3)
SET #loadSide=cast( #storageId as nvarchar(50));
WITH CarriageLoadSiteTreeView (
[CarriageLoadSiteId],RootId,RootName,[Code], Name, ParentID, [LoadSiteType],IsDelete,
CodeSAP,DepartmentId, Capacity, MinLimit, MaxLimit, LoadSitePlaceTypeId) AS
(
SELECT [CarriageLoadSiteId],
[CarriageLoadSiteId] RootId,
Name RootName,
[Code],
Name,
ParentID,
[LoadSiteType],
[IsDelete],
CodeSAP,
DepartmentId,
Capacity,
MinLimit,
MaxLimit,
LoadSitePlaceTypeId
FROM CarriageLoadSite WITH(NOLOCK)
WHERE ISNULL(ParentID,0) =isnull(#storageId,0) AND Isdelete!=1
UNION ALL
SELECT d.[CarriageLoadSiteId],
q.RootId RootId,
RootName RootName,
d.[Code],
d.Name,
d.ParentID,
d.[LoadSiteType],
d.[IsDelete],
d.CodeSAP,
d.DepartmentId,
d.Capacity,
d.MinLimit,
d.MaxLimit,
d.LoadSitePlaceTypeId
FROM CarriageLoadSite AS d WITH(NOLOCK)
INNER JOIN CarriageLoadSiteTreeView AS q ON d.ParentID = q.[CarriageLoadSiteId] WHERE d.IsDelete!=1
)
SELECT
ComplexId,
RootId Id,
cast(RootId as nvarchar(8))+'|Sclad'+IIF(RootId=max(R.CarriageLoadSiteId),'|finish','') [Uid],
RootName CarriageLoadSiteName,
ROUND(SUM(AMOUNT-movement-consumption)/1000,3) Amount,
cast(1 as bit) hasChildren,
T.FullPathId Path,
UparentId=IIF(#parent is null,'',#parent),
[Type]=0,
Petal = IIF(RootId=max(R.CarriageLoadSiteId),'|Sclad|finish','')
FROM (
SELECT
RootId
,RootName
,t.CarriageLoadSiteId
,t.MaterialId
,YEAR(t.Period) [Year]
,MONTH(t.Period) [Month]
,round( case when (t.Amount=0 or t.Amount is null) and (tt.Type=0 or [TypeAmountCarriage]=1 )then carr.[CertifNetto]else t.Amount end ,0 )[Amount]
,t.UnitId
, CarriageId
, tt.TurnoverTypeId
,round(dbo.GetMovementByTurnOverWithTempValue(t.turnoverid),5) movement
,dbo.GetConsumptionByTurnOver(t.turnoverid) consumption
,0 stockBegin
,round(t.Amount,0 ) CommingAmount
,case when (t.Amount=0 or t.Amount is null) and tt.Type=0 then 1 else 0 end [IsNotConfirmed]
,[TypeAmountCarriage]
,M.ComplexId
FROM Turnover t WITH(NOLOCK)
INNER JOIN TurnoverType tt ON tt.TurnoverTypeId = t.TurnoverTypeId
INNER JOIN CarriageLoadSiteTreeView l ON l.CarriageLoadSiteId = t.CarriageLoadSiteId
INNER JOIN [Carriages] carr on carr.[CarriagesID]=t.[CarriageId]
INNER JOIN Material M on M.MaterialID=t.MaterialId
WHERE YEAR(t.Period) = #Year AND
MONTH(t.Period) = #Month AND
l.LoadSiteType = 0 AND
tt.type in (0,5,4) AND
isclear=0 AND
M.MaterialSourceID in (select value from string_split(#materialSourceId, ','))
UNION ALL
SELECT RootId
,RootName
,s.CarriageLoadSiteId
,s.MaterialId
,#Year [Year]
,#Month [Month]
,round(s.Amount,0)
,s.UnitId
,CarriageId
,[TurnoverTypeId]
,round(dbo.GetMovementByStock(s.StockId),5) movement
,dbo.GetConsumptionByStock(s.StockId) consumption
,round(s.Amount,0)-s.spendStock
,0
,0 [IsNotConfirmed]
,[TypeAmountCarriage]
,M.ComplexId
FROM Stock s
INNER JOIN CarriageLoadSiteTreeView l ON l.CarriageLoadSiteId = s.CarriageLoadSiteId
INNER JOIN Material M on M.MaterialID=s.MaterialId
WHERE s.[Year] = #YearPrev AND
s.[Month] = #MonthPrev AND
s.[Type] = 0 AND
l.LoadSiteType = 0 AND
amount >0 AND
isclear=0 AND
M.MaterialSourceID in (select value from string_split(#materialSourceId, ','))
) as R
INNER JOIN CariageLoadSiteTree T on T.CarriageLoadSiteId=RootId
INNER JOIN string_split(#complexIds, ',') MM ON CAST(MM.value AS int) = R.ComplexId
WHERE AMOUNT-movement-consumption>10
GROUP BY RootName,RootId,ComplexId, T.FullPathId
ORDER BY RootName

Operand data type nvarchar(max) is invalid for subtract operator

I am trying to display a table data from database to my application. But when I am trying to pivot the query based on the requirements I am getting the below error.
Operand data type nvarchar(max) is invalid for subtract operator.
Below are the details. Here is my original query.
select Currency1, Currency2,M.MonthName+'-'+YearName as Month, Price
from tbl_Currency C
inner join tbl_Month M on M.monthID = C.monthid
inner join tbl_Year Y on Y.yearid = C.yearid
where C.monthid in ('7') and C.yearid = '5'
Below is the output received
Below is the format required to display data.
Below is the pivot query I tried for formatting the data.
DECLARE #sql as nvarchar(max) ,
#month1 as NVarchar(max) ,
#year1 as nvarchar(max),
#io as nvarchar(max)
set #month1 = '7';
set #year1 = '2';
set #io = (STUFF((SELECT ',[' + Convert(varchar,M.MonthName+''+YearName,50)+']' from
tbl_Currency C inner join tbl_Month M on M.monthID=C.monthid
inner join tbl_Year Y on Y.yearid=C.yearid
where C.monthid IN (#month1 ) and C.yearid IN ( #year1 ) GROUP BY M.CodeName+''+YearName order by M.CodeName+''+YearName
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'),1,1,''));
select #sql = 'select * from (select Currency1, Currency2,((M.CodeName) + (YearName)) as Month,price from
tbl_Currency C inner join tbl_Month M on M.monthID=C.monthid
inner join tbl_Year Y on Y.yearid=C.yearid
where C.monthid = (3) and C.yearid = (2) ) t
PIVOT (
MAX(amount)
FOR Month IN ('+#io+' )
) As pivot_table';
EXEC SP_EXECUTESQL #sql
Below is the output :
How can I achieve a concatenation - in the month and year to get column name as Jul-20. I tried the below query but received error - Operand data type nvarchar(max) is invalid for subtract operator
select #sql = 'select * from (select Currency1, Currency2,((M.CodeName) + '-' + (YearName)) as Month,price from
tbl_Currency C inner join tbl_Month M on M.monthID=C.monthid
inner join tbl_Year Y on Y.yearid=C.yearid
where C.monthid = (3) and C.yearid = (2) ) t
PIVOT (
MAX(amount)
FOR Month IN ('+#io+' )
) As pivot_table';
Sorry for the long post. Tried to explain all the steps done. Any help would be appreciated. Since I am a new user, kindly suggest I can improve the presentation if necessary.
You need to add double quotes around your  - 
like this ((M.CodeName) + '' - '' + (YearName)) AS Month:
SELECT #sql = 'SELECT *
FROM (
SELECT Currency1
,Currency2
,((M.CodeName) + '' - '' + (YearName)) AS Month
,price
FROM tbl_Currency C
INNER JOIN tbl_Month M ON M.monthID = C.monthid
INNER JOIN tbl_Year Y ON Y.yearid = C.yearid
WHERE C.monthid = (3)
AND C.yearid = (2)
) t
PIVOT(MAX(amount) FOR Month IN (' + #io + ')) AS pivot_table
';

Is it always possible to transform multiple spatial selects with while loop and variables into a single query without using temp tables in sql?

This problem can be solved with temp table, however, I don't want to use Temp table or var table, this question is mostly for my personal educational purposes.
I inherited the following SQL:
DECLARE #i int = 993
while #i <=1000
begin
declare #lat nvarchar(20)
select top 1 #lat = SUBSTRING(Address,0,CHARINDEX(',',Address,0)) from dbo.rent
where id = #i;
declare #lon nvarchar(20)
select top 1 #lon = SUBSTRING(Address,CHARINDEX(',',Address)+1,LEN(Address)) from dbo.rent
where id = #i
declare #p GEOGRAPHY = GEOGRAPHY::STGeomFromText('POINT('+ #lat +' '+#lon+')', 4326)
select price/LivingArea sq_m, (price/LivingArea)/avg_sq_m, * from
(select (sum(price)/sum(LivingArea)) avg_sq_m, count(1) cnt, #i id from
(select *, GEOGRAPHY::STGeomFromText('POINT('+
convert(nvarchar(20), SUBSTRING(Address,0,CHARINDEX(',',Address,0)))+' '+
convert( nvarchar(20), SUBSTRING(Address,CHARINDEX(',',Address)+1,LEN(Address)))+')', 4326)
.STBuffer(500).STIntersects(#p) as [Intersects]
from dbo.rent
where Address is not null
) s
where [Intersects] = 1) prox
inner join dbo.rent r on prox.id = r.id
set #i = #i+1
end
it is used to analyze property prices per square meter that are in proximity and compare them to see which ones are cheaper...
Problem: a mechanism for calling has to be moved from C# to SQL and all queries have to be combined into a single result (now you get one row per one while run), i.e #i and #p has to go and become while id < x and id > y or somehow magically joined,
the procedure is a cut down version of actual thing but having a solution to the above I will have no problem making the whole thing work...
I am of the opinion that any SQL mechanism with variables and loops can be transformed to a single SQL statement, hence the question.
SqlFiddle
If I understand your question properly (Remove the need for loops and return one data set) then you can use CTE (Common Table Expressions) for the Lats, Lons and Geog variables.
You;re SQLFIddle was referencing a database called "webanalyser" so I removed that from the query below
However, the query will not return anything as the sample data has wrong data for address column.
;WITH cteLatsLongs
AS(
SELECT
lat = SUBSTRING(Address, 0, CHARINDEX(',', Address, 0))
,lon = SUBSTRING(Address, CHARINDEX(',', Address) + 1, LEN(Address))
FROM dbo.rent
)
,cteGeogs
AS(
SELECT
Geog = GEOGRAPHY ::STGeomFromText('POINT(' + LL.lat + ' ' + LL.lon + ')', 4326)
FROM cteLatsLongs LL
),cteIntersects
AS(
SELECT *,
GEOGRAPHY::STGeomFromText('POINT(' + CONVERT(NVARCHAR(20), SUBSTRING(Address, 0, CHARINDEX(',', Address, 0))) + ' ' + CONVERT(NVARCHAR(20), SUBSTRING(Address, CHARINDEX(',', Address) + 1, LEN(Address))) + ')', 4326).STBuffer(500).STIntersects(G.Geog) AS [Intersects]
FROM dbo.rent
CROSS APPLY cteGeogs G
)
SELECT avg_sq_m = (SUM(price) / SUM(LivingArea)), COUNT(1) cnt
FROM
cteIntersects I
WHERE I.[Intersects] = 1
It can be done, in this specific case 'discovery' that was necessary was the ability to perform JOINs on Point e.g ability to join tables on proximity (another a small cheat was to aggregate point-strings to actual points, but it's just an optimization). Once this is done, a query could be rewritten as follows:
SELECT adds.Url,
adds.Price/adds.LivingArea Sqm,
(adds.Price/adds.LivingArea)/k1.sale1Avg ratio,
*
FROM
(SELECT baseid,
count(k1Rent.rentid) rent1kCount,
sum(k1Rent.RperSqM)/(count(k1Rent.rentid)) AS rent1kAvgSqM,
count(around1k.SaleId) sale1kCount,
(sum(k1sale.price)/sum(k1Sale.LivingArea)) sale1Avg,
(sum(k1sale.price)/sum(k1Sale.LivingArea))/((sum(k1Rent.RperSqM)/(count(k1Rent.rentid)))*12) years --*
FROM
(SELECT sa.id baseid,
s.id saleid,
s.RoomCount,
POINT
FROM SpatialAnalysis sa
INNER JOIN Sale s ON s.Id = SaleId
WHERE sa.SalesIn1kRadiusCount IS NULL) AS base
JOIN SpatialAnalysis around1k ON base.Point.STBuffer(1000).STIntersects(around1k.Point) = 1
LEFT OUTER JOIN
(SELECT id rentid,
rc,
Price/avgRoomSize RperSqM
FROM
(SELECT *
FROM
(SELECT rc,
sum(avgArea*c)/sum(c) avgRoomSize
FROM
(SELECT roomcount rc,
avg(livingarea) avgArea,
count(1) c
FROM Rent
WHERE url LIKE '%systemname%'
AND LivingArea IS NOT NULL
GROUP BY RoomCount
UNION
(SELECT roomcount rc,
avg(livingarea) avgArea,
count(1) c
FROM sale
WHERE url LIKE '%systemname%'
AND LivingArea IS NOT NULL
GROUP BY RoomCount))uni
GROUP BY rc) avgRoom) avgrents
JOIN rent r ON r.RoomCount = avgrents.rc) k1Rent ON k1Rent.rentid =around1k.RentId
AND base.RoomCount = k1Rent.rc
LEFT OUTER JOIN Sale k1Sale ON k1Sale.Id = around1k.SaleId
AND base.RoomCount = k1Sale.RoomCount
GROUP BY baseid) k1
left outer join SpatialAnalysis sp on sp.Id = baseid
left outer join Sale adds on adds.Id = sp.SaleId
where adds.Price < 250000
order by years, ratio

Pivot query in SQL Server

I want to build dynamic sql query based on following
SELECT P.Trackingno,PA.SKUId,SC.SKUName,count(PA.SKUId) as TotalSKUId
,sum(case when PA.IsAvailable = 1 then 1 else 0 end) AS IsAvailable
FROM ADMIN.posavailability PA
LEFT OUTER JOIN Admin.SKUCreation SC ON SC.TCID=PA.Skuid
LEFT OUTER JOIN Admin.POSVisitDetails PD on PD.VisitId=PA.VisitID
LEFT OUTER JOIN Admin.POS P ON P.TrackingNo=PD.TrackingNo
WHERE PA.VisitId in
(SELECT visitid FROM Admin.POSVisitDetails PD WHERE PD.month=2 and PD.year=2017)
and PA.IsActive=1
GROUP BY P.Trackingno,PA.SKUId,SC.SKUName,PD.Month,PD.year
ORDER BY P.Trackingno
I got out as follows:
My desired output is:
Can any one help for dynamic pivot SQL query.
Here maybe help you.
Dynamic sql query
CREATE TABLE TrackingTbl
(
TrackingNo int,
SKUID int,
SKUName varchar(50),
TotalSKUID int,
IsAvaiable int
)
INSERT INTO TrackingTbl VALUES (1234,1,'Red',2,2)
INSERT INTO TrackingTbl VALUES (1234,2,'White',2,1)
INSERT INTO TrackingTbl VALUES (1234,3,'Blue',2,0)
INSERT INTO TrackingTbl VALUES (1234,4,'Yellow',2,2)
INSERT INTO TrackingTbl VALUES (3456,1,'Red',3,3)
INSERT INTO TrackingTbl VALUES (3456,2,'White',3,2)
INSERT INTO TrackingTbl VALUES (3456,3,'Blue',3,1)
INSERT INTO TrackingTbl VALUES (3456,4,'Yellow',3,0)
DECLARE #Columns varchar(200)
SET #Columns = Stuff((SELECT concat(', [',td.SKUName,']') FROM (select DISTINCT tt.SKUName FROM TrackingTbl tt ) td FOR XML PATH (''))
,1,1,'')
DECLARE #Query nvarchar(max) = CONCAT(
'SELECT TrackingNo,TotalSKUID,',#Columns,
' FROM
(
SELECT tt.IsAvaiable, tt.SKUName ,tt.TrackingNo, tt.TotalSKUID
FROM TrackingTbl tt
) sc
PIVOT
(
sum(IsAvaiable) FOR SKuName IN (',#Columns,' )
) pvt')
exec sp_executesql #Query
DROP TABLE dbo.TrackingTbl
Try this using MAX ()
;with cte as (
SELECT P.Trackingno,PA.SKUId,SC.SKUName,count(PA.SKUId) as TotalSKUId
,sum(case when PA.IsAvailable = 1 then 1 else 0 end) AS IsAvailable
FROM ADMIN.posavailability PA
LEFT OUTER JOIN Admin.SKUCreation SC ON SC.TCID=PA.Skuid
LEFT OUTER JOIN Admin.POSVisitDetails PD on PD.VisitId=PA.VisitID
LEFT OUTER JOIN Admin.POS P ON P.TrackingNo=PD.TrackingNo
WHERE PA.VisitId in
(SELECT visitid FROM Admin.POSVisitDetails PD WHERE PD.month=2 and PD.year=2017)
and PA.IsActive=1
GROUP BY P.Trackingno,PA.SKUId,SC.SKUName,PD.Month,PD.year
ORDER BY P.Trackingno
)
select trackingno,totalskuid,max(case when skuname='Red' then isavailable else '' end) Red,
max(case when skuname='White' then isavailable else '' end) White,
max(case when skuname='Blue' then isavailable else '' end) Blue,
max(case when skuname='Yellow' then isavailable else '' end) Yellow
from cte
group by trackingno,totalskuid

selecting random records inside a UDF

I'm writing a function in sql server 2012.
I came to know that we can not use RAND() or NEWID() functions in the select statement of a function in sql server.
My function goes like this:
CREATE FUNCTION Keywordsuggester (#userid INT)
returns #suggestor_tab TABLE (
keywordid INT,
keywordname VARCHAR(max),
keywordcategory VARCHAR(max))
AS
BEGIN
DECLARE #category_table TABLE
(
category_name VARCHAR(max),
category_id INT,
rownum INT
)
DECLARE #ID INT = 1
DECLARE #COUNT INT = 0
DECLARE #I INT = 1
INSERT INTO #category_table
SELECT kc.NAME,
kc.id,
k.NAME,
d.NAME,
Row_number()
OVER(
ORDER BY d.id ASC) AS rownum
FROM dtypes d
JOIN keywords k
ON d.NAME LIKE '%' + k.NAME + '%'
JOIN keywordscategory kc
ON k.categoryid = kc.id
WHERE d.userid = #userid
SELECT #count = rownum
FROM #category_table
WHILE #count > #I
BEGIN
INSERT INTO #suggestor_tab
SELECT TOP 5 kc.id,
k.NAME,
kc.NAME
FROM kwords k
JOIN #category_table ct
ON k.categoryid = ct.category_id
JOIN kwcategory kc
ON kc.NAME = ct.category_name
WHERE ct.rownum = #I
--Here I'm inserting top 5 records for each category into the suggestor_tab,instead I have to insert random 5 records for each category(i.e.,#I)
SET #I=#I + 1
--return
END
INSERT INTO #suggestor_tab
SELECT kc.id,
k.NAME,
kc.NAME
FROM kwords k
JOIN #category_table ct
ON k.categoryid = ct.category_id
JOIN kwcategory kc
ON kc.NAME = category_name
RETURN
END
How can I get random records for each category(i.e., #I in the while loop).
I tried the query like:
SELECT TOP 5 k.NAME
FROM kwords k
JOIN #category_table ct
ON k.category_id = ct.id
JOIN kwcategory kc
ON kc.NAME = category_name
WHERE ct.rownum = #I
ORDER BY Newid()
which throws an error like:
Invalid use of a side-effecting operator 'newid' within a function.
Is there anyway to do this?
Thanks in advance.
You cannot use Non-deterministic Funcions inside UDF.
Create a View and use it in order by
create view Random
as
select newid() as New_id
Change you select something like this.
SELECT TOP 5 k.NAME
FROM KWords k
JOIN #category_table ct
ON k.category_id = ct.id
JOIN kwcategory kc
ON kc.NAME = category_name
WHERE ct.rownum = #I
ORDER BY (SELECT new_id
FROM random)

Resources