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.