Aggregate Functions for TempTable - tsql

Scenario:
I use tempTable (# temporary table) in SQL Server 2008 R2 in a stored procedure, and I need to use aggregate functions such as MIN(), MAX() and ... to perform a series of calculations on the temp table's columns.
But, temp table doesn't have any aggregate functions. Now what's the best solution for this problem ?
Thanks
Update:
I want to obtain Minimum Remain of customer's Bank Account in today Transactions
CREATE TABLE #TempTableToday
(
DetailAccountId BIGINT,
RemainToday BIGINT,
Profit DECIMAL(18, 6),
LastDate DATETIME
);
CREATE TABLE #TempTableMinRemainToday
(
DetailAccount2Id BIGINT,
MinRemainToday DECIMAL(18, 2)
);
DECLARE AccountionDocDetailsToday_CURSOR CURSOR
FOR
---------- Get Today Transaction for each Customer's Bank Account ---------
SELECT Account.AccountingDocsDetail.Id,
Account.AccountingDocsDetail.AccountingDocId,
Account.AccountingDocsDetail.AccountId,
Account.AccountingDocsDetail.DetailAccountId,
Account.AccountingDocsDetail.Debit,
Account.AccountingDocsDetail.Credit,
Account.AccountingDocsDetail.DateIn
FROM Account.AccountingDocsDetail,
Account.AccountingDocs,
[Transaction].[Transaction],
Account.Accounts
WHERE Account.AccountingDocsDetail.AccountingDocId = Account.AccountingDocs.Id
AND Account.AccountingDocs.Id = [Transaction].[Transaction].AccountingDocId
AND Account.AccountingDocsDetail.AccountId = Account.Accounts.Id
AND Account.Accounts.Code LIKE '21%'
AND Account.AccountingDocsDetail.DateIn = GETDATE()
OPEN AccountionDocDetailsToday_CURSOR
FETCH NEXT FROM AccountionDocDetailsToday_CURSOR INTO #Id,#AccountingDocId,
#AccountId,#DetailAccountId,#Credit,#Debit,#DateAccountindoc
WHILE (##FETCH_STATUS <> -1)
BEGIN
DECLARE #lastDateTime DATETIME
DECLARE #AccNumber NVARCHAR(50)
DECLARE #BankAccSettingId BIGINT
DECLARE #Profit DECIMAL(18, 6)
----- Customer's Account Number-----
SELECT #AccNumber = DetailCode
FROM Account.DetailAccount
WHERE Id = #DetailAccountId
SELECT #BankAccSettingId = BankAccSettingId
FROM Account.BankAccount
WHERE AccountNumber = #AccNumber
SELECT #Profit = ProfitInYear
FROM Account.BankAccountSetting
WHERE Id = #BankAccSettingId
SELECT #RemainToday = dbo.FnCalMandeh(#DetailAccountId, #AccountingDocId)
INSERT INTO #TempTableToday
(
DetailAccountId,
RemainToday,
Profit,
LastDate
)
VALUES
(
#DetailAccountId,
#RemainToday,
ISNULL(#Profit, 0),
#DateAccountindoc
);
-- I try to obtain: Minimum Remain of Bank Account in today Transactions
SELECT #MinRemainToday2 = MIN(#TempTableToday.RemainToday)
FROM #TempTableToday
WHERE #TempTableToday.DetailAccountId = #DetailAccountId
INSERT INTO #TempTableMinRemainToday
(
DetailAccount2Id,
MinRemainToday
)
VALUES
(
#DetailAccountId,
#MinRemainToday2
);
CLOSE AccountionDocDetailsToday_CURSOR
DEALLOCATE AccountionDocDetailsToday_CURSOR
END
CREATE TABLE #TempTableToday
(
DetailAccountId BIGINT,
RemainToday BIGINT,
Profit DECIMAL(18, 6),
LastDate DATETIME
);
CREATE TABLE #TempTableMinRemainToday
(
DetailAccount2Id BIGINT,
MinRemainToday DECIMAL(18, 2)
);
DECLARE AccountionDocDetailsToday_CURSOR CURSOR
FOR
---------- Get Today Transaction for each Customer's Bank Account ---------
SELECT Account.AccountingDocsDetail.Id,
Account.AccountingDocsDetail.AccountingDocId,
Account.AccountingDocsDetail.AccountId,
Account.AccountingDocsDetail.DetailAccountId,
Account.AccountingDocsDetail.Debit,
Account.AccountingDocsDetail.Credit,
Account.AccountingDocsDetail.DateIn
FROM Account.AccountingDocsDetail,
Account.AccountingDocs,
[Transaction].[Transaction],
Account.Accounts
WHERE Account.AccountingDocsDetail.AccountingDocId = Account.AccountingDocs.Id
AND Account.AccountingDocs.Id = [Transaction].[Transaction].AccountingDocId
AND Account.AccountingDocsDetail.AccountId = Account.Accounts.Id
AND Account.Accounts.Code LIKE '21%'
AND Account.AccountingDocsDetail.DateIn = GETDATE()
OPEN AccountionDocDetailsToday_CURSOR
FETCH NEXT FROM AccountionDocDetailsToday_CURSOR INTO #Id,#AccountingDocId,
#AccountId,#DetailAccountId,#Credit,#Debit,#DateAccountindoc
WHILE (##FETCH_STATUS <> -1)
BEGIN
DECLARE #lastDateTime DATETIME
DECLARE #AccNumber NVARCHAR(50)
DECLARE #BankAccSettingId BIGINT
DECLARE #Profit DECIMAL(18, 6)
----- Customer's Account Number-----
SELECT #AccNumber = DetailCode
FROM Account.DetailAccount
WHERE Id = #DetailAccountId
SELECT #BankAccSettingId = BankAccSettingId
FROM Account.BankAccount
WHERE AccountNumber = #AccNumber
SELECT #Profit = ProfitInYear
FROM Account.BankAccountSetting
WHERE Id = #BankAccSettingId
SELECT #RemainToday = dbo.FnCalMandeh(#DetailAccountId, #AccountingDocId)
INSERT INTO #TempTableToday
(
DetailAccountId,
RemainToday,
Profit,
LastDate
)
VALUES
(
#DetailAccountId,
#RemainToday,
ISNULL(#Profit, 0),
#DateAccountindoc
);
-- I try to obtain: Minimum Remain of Bank Account in today Transactions
SELECT #MinRemainToday2 = MIN(#TempTableToday.RemainToday)
FROM #TempTableToday
WHERE #TempTableToday.DetailAccountId = #DetailAccountId
INSERT INTO #TempTableMinRemainToday
(
DetailAccount2Id,
MinRemainToday
)
VALUES
(
#DetailAccountId,
#MinRemainToday2
);
CLOSE AccountionDocDetailsToday_CURSOR
DEALLOCATE AccountionDocDetailsToday_CURSOR
END

Please try this. I am still a bit unclear on the functionality but my best guess is that you are having the MIN() inside the loop so its only returning one value. I have moved it outside the loop so best case is that it will retrieve the MIN() of a set. You will have to modify this query a bit to merge with your query.
IF OBJECT_ID(N'tempdb..#AccountingDocsDetail') > 0
DROP TABLE #AccountingDocsDetail
IF OBJECT_ID(N'tempdb..#TempTableToday') > 0
DROP TABLE #TempTableToday
IF OBJECT_ID(N'tempdb..#TempTableMinRemainToday') > 0
DROP TABLE #TempTableMinRemainToday
CREATE TABLE #AccountingDocsDetail
(
Id INT,
AccountingDocId INT,
AccountId INT,
DetailAccountId INT,
Debit DECIMAL(18, 6),
Credit DECIMAL(18, 6),
DateIn DATETIME
)
INSERT INTO #AccountingDocsDetail (Id, AccountingDocId, AccountId, DetailAccountId, Debit, Credit, DateIn)
VALUES
(1, 2, 1, 1, '100.00', '0.00', '2014-08-03 13:44:32.100'),
(1, 2, 1, 1, '0.00', '30.00', '2014-08-03 13:46:32.100'),
(1, 2, 1, 1, '0.00', '30.00', '2014-08-03 13:48:32.100'),
(1, 2, 1, 1, '0.00', '40.00', '2014-08-03 13:54:32.100'),
(1, 2, 1, 1, '100.00', '0.00', '2014-08-03 14:44:32.100')
SELECT *
FROM #AccountingDocsDetail add1
CREATE TABLE #TempTableToday
(
DetailAccountId BIGINT,
RemainToday BIGINT,
Profit DECIMAL(18, 6),
LastDate DATETIME
);
CREATE TABLE #TempTableMinRemainToday
(
DetailAccount2Id BIGINT,
MinRemainToday DECIMAL(18, 2)
);
DECLARE #AccountingDocId INT
DECLARE #DetailAccountId INT
DECLARE #Debit DECIMAL(18, 6)
DECLARE #Credit DECIMAL(18, 6)
DECLARE #DateAccountindoc DATETIME
DECLARE #StartLoop INT
DECLARE #EndLoop INT
DECLARE #MinRemainToday2 INT
DECLARE #LoopTable TABLE
(
ltId INT IDENTITY(1, 1),
Id INT,
AccountingDocId INT,
AccountId INT,
DetailAccountId INT,
Debit DECIMAL(18, 6),
Credit DECIMAL(18, 6),
DateIn DATETIME
)
INSERT INTO #LoopTable
SELECT ad.Id,
ad.AccountingDocId,
ad.AccountId,
ad.DetailAccountId,
ad.Debit,
ad.Credit,
ad.DateIn
FROM #AccountingDocsDetail AS ad
--By casting to date all transactions from 12AM - 12PM is covered
WHERE CAST(ad.DateIn AS DATE) = CAST(GETDATE() AS DATE)
SELECT #StartLoop = MIN(lt.ltId),
#EndLoop = MAX(lt.ltId)
FROM #LoopTable lt
WHILE #StartLoop <= #EndLoop
BEGIN
DECLARE #RemainToday INT
DECLARE #AccNumber NVARCHAR(50)
DECLARE #BankAccSettingId BIGINT
DECLARE #Profit DECIMAL(18, 6)
SELECT --lt.Id,
-- lt.AccountingDocId,
-- lt.AccountId,
#DetailAccountId = lt.DetailAccountId
--lt.Debit,
--lt.Credit,
--lt.DateIn
FROM #LoopTable lt
WHERE lt.ltId = #StartLoop
----- Customer's Account Number-----
SELECT #AccNumber = DetailCode
FROM Account.DetailAccount
WHERE Id = #DetailAccountId
SELECT #BankAccSettingId = BankAccSettingId
FROM Account.BankAccount
WHERE AccountNumber = #AccNumber
SELECT #Profit = ProfitInYear
FROM Account.BankAccountSetting
WHERE Id = #BankAccSettingId
SELECT #RemainToday = dbo.FnCalMandeh(#DetailAccountId, #AccountingDocId)
INSERT INTO #TempTableToday (DetailAccountId, RemainToday, Profit, LastDate)
VALUES (#DetailAccountId, #RemainToday, ISNULL(#Profit, 0), #DateAccountindoc);
SET #StartLoop = #StartLoop + 1
END
-- I try to obtain: Minimum Remain of Bank Account in today Transactions
SELECT #MinRemainToday2 = MIN(ttt.RemainToday)
FROM #TempTableToday ttt
WHERE ttt.DetailAccountId = #DetailAccountId
INSERT INTO #TempTableMinRemainToday (DetailAccount2Id,MinRemainToday)
VALUES (#DetailAccountId,#MinRemainToday2);
SELECT DetailAccount2Id,MinRemainToday
FROM #TempTableMinRemainToday

Related

Calculating the business differences in sql in the form of day, hours and minutes - SQL Server

With the below function I getting the result as 00:09:10 however I want the result to be as 01:00:10.
So hours is considered as considered as 1 day.
Example if hours is 30 then it will be 03:03:00 and so on
fn_GetHolidayMinutes : Get holiday in minutes between two dates and country
CREATE FUNCTION [dbo].[fn_GetHolidayMinutes]
(#StartDate DATETIME,
#EndDate DATETIME,
#CountryId BIGINT)
RETURNS BIGINT
AS
BEGIN
DECLARE #OUTPUT BIGINT;
DECLARE #HolidayList TABLE (HolidaysDate DATE)
-- Create Table #HolidayList
-- (
-- HolidaysDate date
-- )
DECLARE #Date1 DATE, #Date2 DATE
DECLARE holiday_cursor CURSOR FOR
SELECT StartDate,EndDate
FROM Holidays
WHERE IsActive = 1
AND CountryId = #CountryId
AND ((StartDate BETWEEN #StartDate AND #EndDate) OR
(EndDate BETWEEN #StartDate AND #EndDate))
OPEN HOLIDAY_CURSOR
FETCH NEXT FROM HOLIDAY_CURSOR INTO #Date1, #Date2
WHILE ##FETCH_STATUS = 0
BEGIN
--INSERT INTO #HolidayList
INSERT INTO #HolidayList
SELECT DATEADD(DAY, number, #Date1) [Date]
FROM master..spt_values
WHERE type = 'P'
AND DATEADD(DAY, number, #Date1) <= #Date2
FETCH NEXT FROM HOLIDAY_CURSOR INTO #Date1, #Date2
END
CLOSE HOLIDAY_CURSOR;
DEALLOCATE HOLIDAY_CURSOR;
(SELECT #OUTPUT= COUNT(DISTINCT HolidaysDate)
FROM #HolidayList
WHERE HolidaysDate BETWEEN #StartDate AND #EndDate
AND DATEPART(dw, HolidaysDate) NOT IN (SELECT DISTINCT number
FROM master..spt_values
WHERE number BETWEEN 1 and 7
AND number NOT IN (SELECT WorkingDay
FROM WorkingDays
WHERE CountryId = #CountryId AND IsActive = 1)
))
---print #OUTPUT; --this will give in days
--get the output in minutes
RETURN #OUTPUT * (SELECT TOP 1 STUFF(WorkingHours, 2, 2, '')
FROM dbo.WorkingDays
WHERE CountryId = #CountryId) * 60;
END
fn_GetWorkingDayMinuts :
CREATE FUNCTION [dbo].[fn_GetWorkingDayMinuts]
(#StartDate DATETIME,
#EndDate DATETIME,
#CountryId BIGINT)
--RETURNS BIGINT
RETURNS VARCHAR(250)
AS
BEGIN
DECLARE #Temp BIGINT
SET #Temp = 0
DECLARE #FirstDay DATE
SET #FirstDay = CONVERT(DATE, #StartDate, 112)
DECLARE #LastDay DATE
SET #LastDay = CONVERT(DATE, #EndDate, 112)
DECLARE #StartTime TIME
SET #StartTime = CONVERT(TIME, #StartDate)
DECLARE #FinishTime TIME
SET #FinishTime = CONVERT(TIME, #EndDate)
DECLARE #WorkStart TIME
SET #WorkStart = (SELECT CONVERT(VARCHAR(5),CONVERT(TIME, CONVERT(VARCHAR,CONVERT(DATE, GETDATE()))+ ' ' + (SELECT TOP 1
WorkStartTime FROM WorkingDays WHERE CountryId=#CountryId), 120)))
DECLARE #WorkFinish TIME
SET #WorkFinish = (SELECT CONVERT(VARCHAR(5),CONVERT(TIME, CONVERT(VARCHAR,CONVERT(DATE, GETDATE()))+ ' ' + (SELECT TOP 1
WorkEndTime FROM WorkingDays WHERE CountryId=#CountryId), 120)))
DECLARE #DailyWorkTime BIGINT
SET #DailyWorkTime = DATEDIFF(MINUTE, #WorkStart, #WorkFinish)
IF (#StartTime<#WorkStart)
BEGIN
SET #StartTime = #WorkStart
END
IF (#FinishTime>#WorkFinish)
BEGIN
SET #FinishTime=#WorkFinish
END
IF (#FinishTime<#WorkStart)
BEGIN
SET #FinishTime=#WorkStart
END
IF (#StartTime>#WorkFinish)
BEGIN
SET #StartTime = #WorkFinish
END
DECLARE #CurrentDate DATE
SET #CurrentDate = #FirstDay
DECLARE #LastDate DATE
SET #LastDate = #LastDay
WHILE(#CurrentDate<=#LastDate)
BEGIN
--IF (DATEPART(dw, #CurrentDate)!=1 AND DATEPART(dw, #CurrentDate)!=7)
IF(DATEPART(dw, #CurrentDate) IN (SELECT distinct number FROM master..spt_values WHERE number BETWEEN 1 and 7
AND number NOT IN (SELECT
WorkingDay FROM WorkingDays where CountryId=#CountryId and IsActive=1)
))
BEGIN
IF (#CurrentDate!=#FirstDay) AND (#CurrentDate!=#LastDay)
BEGIN
SET #Temp = #Temp + #DailyWorkTime
END
--IF it starts at startdate and it finishes not this date find diff between work finish and start as minutes
ELSE IF (#CurrentDate=#FirstDay) AND (#CurrentDate!=#LastDay)
BEGIN
SET #Temp = #Temp + DATEDIFF(MINUTE, #StartTime, #WorkFinish)
END
ELSE IF (#CurrentDate!=#FirstDay) AND (#CurrentDate=#LastDay)
BEGIN
SET #Temp = #Temp + DATEDIFF(MINUTE, #WorkStart, #FinishTime)
END
--IF it starts and finishes in the same date
ELSE IF (#CurrentDate=#FirstDay) AND (#CurrentDate=#LastDay)
BEGIN
SET #Temp = DATEDIFF(MINUTE, #StartTime, #FinishTime)
END
END
SET #CurrentDate = DATEADD(day, 1, #CurrentDate)
END
-- Return the result of the function
IF #Temp<0
BEGIN
SET #Temp=0
END
--RETURN #Temp -(dbo.fn_GetHolidayMinutes (DATEADD(dd, 0, DATEDIFF(dd, 0, #StartDate)),DATEADD(dd, 0, DATEDIFF(dd, 0,
#EndDate)),#CountryId))
--RETURN #Temp
DECLARE #theMinutes INT
DECLARE #Result VARCHAR(250)
SET #theMinutes = #Temp -(dbo.fn_GetHolidayMinutes (DATEADD(dd, 0,
DATEDIFF(dd, 0, #StartDate)),DATEADD(dd, 0, DATEDIFF(dd, 0,
#EndDate)),#CountryId))
--SET #Result= concat((#theMinutes / 540),':' , (#theMinutes % 540) /
60, ':', (#theMinutes % 60))
SET #Result= concat((#theMinutes / ((SELECT TOP 1
STUFF(WorkingHours,2,2,'') FROM dbo.WorkingDays WHERE
CountryId=#CountryId) * 60)),':' , (#theMinutes % ((SELECT TOP 1
STUFF(WorkingHours,2,2,'') FROM dbo.WorkingDays WHERE
CountryId=#CountryId) * 60)) / 60, ':', (#theMinutes % 60))
RETURN #Result
END
So where to modify to the result as
BUSINESS HOURS CREATE DATE & TIME FIRST APPLY (DATE & TIME) TAT TIME CALCULATION RESULT
08h00-17h00: 9hrs/day 12-FEB-19 14:20 13-FEB-19 14:30 00:02:40 + 00:06:30 = 00:09:10 01:00:10

Generate Row number Automatically if only one Record is fetching

ALTER PROCEDURE [dbo].[SerailNo_LoadValue]
(
#SerialNo int,
#Season nchar(5)
)
AS
BEGIN
IF EXISTS (SELECT 1 FROM MATERIAL_Stock WHERE SerialNo = #SerialNo and Season = #Season)
BEGIN
if(#Season = 'PER')
BEGIN
SELECT material_code,ULC_id,setNo,MONTH(GETDATE())AS Delivery_Month,YEAR(GETDATE())AS Delivery_Year,1 AS NORECORD
,ISNULL(qty_total,0) AS qty_total,ISNULL(ULC,0) AS 'ulsmtr',isnull(MATNR,'') as MATNR --ADDED BY LALIT AS DISCUSSED WITH DIPENDRA ON 22 APRIL 2016
FROM MATERIAL_Stock LEFT JOIN ULC_master ON ULC_master.ID =MATERIAL_Stock.ULC_id WHERE SerialNo = #SerialNo and Season = #Season
END
ELSE
BEGIN
SELECT material_code,ULC_id,setNo,Delivery_Month,Delivery_Year,1 AS NORECORD
,ISNULL(qty_total,0) AS qty_total,ISNULL(ULC,0) AS 'ulsmtr',isnull(MATNR,'') as MATNR --ADDED BY LALIT AS DISCUSSED WITH DIPENDRA ON 22 APRIL 2016
FROM MATERIAL_Stock LEFT JOIN ULC_master ON ULC_master.ID =MATERIAL_Stock.ULC_id WHERE SerialNo = #SerialNo and Season = #Season
END
select distinct Delivery_Year, Delivery_Month, Season into #T from Material_stock
where Season=#Season
order by Delivery_Year,Delivery_Month
select *,ROW_NUMBER() OVER (ORDER BY Delivery_Year,Delivery_Month) AS RowNumber into #TT from #T
declare #MONTH int
declare #YEAR int
declare #ROWID int
select top 1 #MONTH=Delivery_Month,#YEAR=Delivery_Year from dbo.Material_stock where Season=#Season And SerialNo=#SerialNo
select #ROWID=RowNumber from #TT where Delivery_Month=#MONTH and Delivery_Year=#YEAR
select Delivery_Year as Delivery_Month1 , Delivery_Month, Delivery_Year, Season,RowNumber from #TT where RowNumber>=#ROWID
drop table #T
drop table #TT
END
END

Can I insert a dynamic number of rows into a table using values from the table?

I want to insert a dynamic number of rows into a table, based on information in that table.
I can do it using the code below, but I'm wondering if there's a way to avoid the loop.
The commented out section was my best attempt at what I was trying to do, but it gave me an error of:
"The reference to column "iCount" is not allowed in an argument to a TOP, OFFSET, or FETCH clause. Only references to columns at an outer scope or standalone expressions and subqueries are allowed here."
DECLARE #TableX TABLE (
TDate DATE
, TType INT
, Fruit NVARCHAR(20)
, Vegetable NVARCHAR(20)
, Meat NVARCHAR(20)
, Bread NVARCHAR(20)
)
INSERT INTO #TableX VALUES
('2016-11-10',1,'Apple','Artichoke',NULL,NULL)
, ('2016-11-10',1,'Banana','Beet',NULL,NULL)
, ('2016-11-10',1,'Canteloupe','Cauliflower',NULL,NULL)
, ('2016-11-10',1,'Durian','Daikon',NULL,NULL)
, ('2016-11-10',2,NULL,NULL,'Rabbit','Rye')
, ('2016-11-10',2,NULL,NULL,'Sausage','Sourdough')
, ('2016-11-11',1,'Elderberry','Eggplant',NULL,NULL)
, ('2016-11-11',2,NULL,NULL,'Turkey','Tortilla')
, ('2016-11-11',2,NULL,NULL,'Venison','Vienna')
SELECT * FROM #TableX
DECLARE #BlankRow TABLE (
ID INT IDENTITY
, TDate DATE
, TType INT
, iCount INT
)
DECLARE #Counter1 INT = 0
, #RowCount INT
; WITH BR1
AS (
SELECT TDate, TType, COUNT(*) AS iCount
FROM #TableX
WHERE TType = 1
GROUP BY TDate, TType
)
, BR2
AS (
SELECT TDate, TType, COUNT(*) AS iCount
FROM #TableX
WHERE TType = 2
GROUP BY TDate, TType
)
INSERT INTO #BlankRow
SELECT ISNULL(BR1.TDate, BR2.TDate) AS TDate,
CASE WHEN ISNULL(BR1.iCount,0) < ISNULL(BR2.iCount,0) THEN 1 ELSE 2 END AS TType,
ABS(ISNULL(BR1.iCount,0) - ISNULL(BR2.iCount,0)) AS iCount
FROM BR1
FULL JOIN BR2
ON BR1.TDate = BR2.TDate
WHILE #Counter1 < (SELECT MAX(ID) FROM #BlankRow)
BEGIN
SET #Counter1 += 1
SET #RowCount = (SELECT iCount FROM #BlankRow WHERE ID = #Counter1)
INSERT INTO #TableX
SELECT TOP (#RowCount) tx.TDate, br.TType, NULL, NULL, NULL, NULL
FROM #TableX tx
LEFT JOIN #BlankRow br
ON tx.TDate = br.TDate
WHERE br.ID = #Counter1
END
/*INSERT INTO #TableX
SELECT TOP (tx.iCount) tx.TDate, br.TType, NULL, NULL, NULL, NULL
FROM #TableX tx
JOIN #BlankRow br
ON tx.TDate = br.TDate*/
SELECT *
FROM #TableX
ORDER BY TDate, TType,
ISNULL(Fruit,REPLICATE(CHAR(255),20)),
ISNULL(Vegetable,REPLICATE(CHAR(255),20)),
ISNULL(Meat,REPLICATE(CHAR(255),20)),
ISNULL(Bread,REPLICATE(CHAR(255),20))
The data is silly, I know, but my end goal is to have two different Tablix's in ReportBuilder that end up with the same number of rows so the headers of my groups show up at the same place on the page.
Something like this:
declare #TableX table(TDate date
,TType int
,Fruit nvarchar(20)
,Vegetable nvarchar(20)
,Meat nvarchar(20)
,Bread nvarchar(20)
);
insert into #TableX values
('2016-11-10',1,'Apple','Artichoke',NULL,NULL)
,('2016-11-10',1,'Banana','Beet',NULL,NULL)
,('2016-11-10',1,'Canteloupe','Cauliflower',NULL,NULL)
,('2016-11-10',1,'Durian','Daikon',NULL,NULL)
,('2016-11-10',2,NULL,NULL,'Rabbit','Rye')
,('2016-11-10',2,NULL,NULL,'Sausage','Sourdough')
,('2016-11-11',1,'Elderberry','Eggplant',NULL,NULL)
,('2016-11-11',2,NULL,NULL,'Turkey','Tortilla')
,('2016-11-11',2,NULL,NULL,'Venison','Vienna');
with DataRN as
(
select *
,row_number() over (partition by TDate, TType order by TDate) rn
from #TableX
)
,RowsRN as
(
select tt.TDate
,tt.TType
,td.rn
from (select distinct TDate, TType
from #TableX
) tt
full join (select distinct t1.TDate
,row_number() over (partition by t1.TDate, t1.TType order by t1.TDate) rn
from #TableX t1
) td
on(tt.TDate = td.TDate)
)
select r.TDate
,r.TType
,d.Fruit
,d.Vegetable
,d.Meat
,d.Bread
from DataRN d
full join RowsRN r
on(d.TDate = r.TDate
and d.TType = r.TType
and d.rn = r.rn
)
order by r.TDate
,r.TType
,isnull(d.Fruit,REPLICATE(CHAR(255),20))
,isnull(d.Vegetable,REPLICATE(CHAR(255),20))
,isnull(d.Meat,REPLICATE(CHAR(255),20))
,isnull(d.Bread,REPLICATE(CHAR(255),20))
In response to your comment, here is how you would use another cte to generate the full list of dates that you would need, if you havn't got a Dates reference table already (These are tremendously useful):
declare #MinDate date = (select min(TDate) from #TableX);
declare #MaxDate date = (select max(TDate) from #TableX);
with Dates as
(
select #MinDate as DateValue
union all
select dateadd(d,1,DateValue)
from Dates
where DateValue < #MaxDate
)
select DateValue
from Dates
option (maxrecursion 0);

SQL query to get the below output

Need help for query:
Id Name Balance
1 A 10
2 A -10
3 A 10
4 A 15
5 B 10.5
6 B -10.5
7 B 25
Requirement: I want to remove the balance with +ve and –ve values for each name. I am expecting the below output
Expected results: --
Id Name Balance
1 A 10
2 A 15
3 B 25
Can you please share me SQL query.
Here is one way to do it.
Create dummy data for testing
CREATE TABLE foo (Id INT, Name VARCHAR(50), Balance money);
INSERT INTO foo VALUES (1, 'A', 10);
INSERT INTO foo VALUES (2, 'A', -10);
INSERT INTO foo VALUES (3, 'A', 10);
INSERT INTO foo VALUES (4, 'A', 15);
INSERT INTO foo VALUES (5, 'B', 10.5);
INSERT INTO foo VALUES (6, 'B', -10.5);
INSERT INTO foo VALUES (7, 'B', 25);
1) Create a temp table that has one extra MatchFound column to record whether a match is found.
CREATE TABLE #TempTable(Id int, Name varchar(50), Balance decimal(10,2), MatchFound bit);
INSERT INTO #TempTable (Id, Name, Balance, MatchFound)
SELECT Id, Name, Balance, 0
FROM foo;
2) Loop through the data to find a match for each row. Update MatchFound column if a match is found.
DECLARE #Id INT, #Name VARCHAR(50), #Balance decimal(10,2), #MatchId INT;
DECLARE MyCursor CURSOR FOR SELECT Id, Name, Balance FROM #TempTable ORDER BY Id;
OPEN MyCursor
FETCH NEXT FROM MyCursor INTO #Id, #Name, #Balance
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS (SELECT 1 FROM #TempTable WHERE Id = #Id AND MatchFound = 0)
BEGIN
SET #MatchId = NULL
SELECT TOP 1 #MatchId = Id FROM #TempTable
WHERE Id <> #Id AND Name = #Name AND Balance = #Balance * -1 AND MatchFound = 0
IF #MatchId IS NOT NULL
UPDATE #TempTable SET MatchFound = 1 WHERE Id IN (#Id, #MatchId)
END
FETCH NEXT FROM MyCursor INTO #Id, #Name, #Balance
END
CLOSE MyCursor;
DEALLOCATE MyCursor;
3) Select and return rows that did not have a match
Select Id, Name, Balance From #TempTable Where MatchFound = 0
4) Clean up
drop table #TempTable

reuse table data in round robin manner

Let us say I have some data I would like to repeat N times. A naive approach would be this:
IF OBJECT_ID('dbo.Data', 'U') IS NOT NULL
DROP TABLE dbo.Data
CREATE TABLE Data
(
DataId INT NOT NULL PRIMARY KEY,
DataValue NVARCHAR(MAX) NOT NULL
)
INSERT INTO Data (DataId, DataValue)
SELECT 1, 'Value1' UNION ALL
SELECT 2, 'Value2' UNION ALL
SELECT 3, 'Value3' UNION ALL
SELECT 4, 'Value4' UNION ALL
SELECT 5, 'Value5'
DECLARE #RowsRequired INT
DECLARE #Counter INT
DECLARE #NumberOfRows INT
SET #RowsRequired = 22
IF OBJECT_ID('tempdb..#TempData') IS NOT NULL DROP TABLE #TempData
CREATE TABLE #TempData
(
Id INT IDENTITY(1,1),
DataValue NVARCHAR(MAX)
)
SELECT #NumberOfRows = COUNT(*) FROM Data
SET #Counter = 1
WHILE #RowsRequired > 0
BEGIN
INSERT INTO #TempData
SELECT DataValue FROM Data WHERE DataId = #Counter
SET #Counter = #Counter + 1
SET #RowsRequired = #RowsRequired - 1
IF(#Counter > #NumberOfRows)
BEGIN
SET #Counter = 1
END
END
SELECT * FROM #TempData
Here #RowsRequired determines how many rows are required. Could this be rephrased in a set based form? Thanks.
Here is a SQLFiddle with the code.
Try this instead:
DECLARE #RowsRequired INT = 22
;WITH CTE AS
(
SELECT DataId, DataValue, ROW_NUMBER() over (PARTITION BY DataId ORDER BY DataId) sort
FROM DATA
CROSS JOIN
(
SELECT TOP (#RowsRequired) 0 d
FROM master..spt_values
) d
)
SELECT TOP (#RowsRequired) ROW_NUMBER() over (order by sort), DataValue
FROM CTE
ORDER BY sort, 1
I tried this and worked for me.
declare #requiredrows int
set #requiredrows = 22;
declare #foreachrow int
select #foreachrow = #requiredrows / Count(*) from Data;
select top (#requiredrows) * from
(
select *, ROW_NUMBER() over(partition by dataId order by number) rno
from Data
Cross Join master..spt_values
) A
where rno <= #foreachrow + 1
Hope it will help.