SQL Right Join? - sql

Arrrgh, I am not getting this.
I have a table of accounts from Dynamics GP that has 7 columns. I need to fill in the blank months for accounts that didn't have any activity for a given month.
I have created an in memory table #MONTHS that has lines like so:
Account, Description, Year, Month, Month Name, Netchange, PeriodBal
1110000, NULL, 2006, 1, NULL, 0, NULL
This should match up with the same information coming from Dynamics GP. A similar line from GP would look like this:
1110000, Petty Cash, 2006, 1, January, 15.00, 343.97
If we did not spend any petty cash in February, then there would be no line for that account in 2/2006, I want to make the #MONTHS table RIGHT JOIN with the DynamicsGP table so that empty months are filled in.
Here's the abbreviated SQL shortened for readability:
SELECT Z.GPACCOUNTNO,
Z.DESCRIPTION,
Z.FISCALYEAR,
Z.FISCALPERIOD,
Z.FISCALPERIODNAME,
Z.NETCHANGE,
Z.PERIODBALANCE
FROM Z
RIGHT JOIN #MONTHS M
ON Z.GPACCOUNTNO = M.GPACCOUNTNO
AND Z.FISCALPERIOD = M.FISCALPERIOD
AND Z.FISCALYEAR = M.FISCALYEAR
The SQL just runs forever. (i.e. 5 minutes before I lose my patience)
I have verified that my #MONTHS table looks like I intend. I have tried doing a "UNION ALL" with the two tables and it gives me duplicates.
If Table Z does not have a current line for a given account/year/month, I want my #MONTHS table to add that line with a Netchange balance of 0.
Thank you for your help. The full SQL is below.
/* Create in memory table to hold account numbers */
DECLARE #i int
DECLARE #c int
DECLARE #ACCT char(129)
DECLARE #numrows int
DECLARE #numyears int
DECLARE #y int
DECLARE #m int
DECLARE #ACCT_TABLE TABLE (
idx smallint Primary Key IDENTITY(1,1),
account char(129)
)
/* Populate account number table */
INSERT #ACCT_TABLE
select distinct ACTNUMST from SBM01.[dbo].[GL00105]
/* Year table reads available years in the DB */
DECLARE #YEAR_TABLE TABLE (
idx smallint Primary Key IDENTITY(1,1),
YEAR1 smallint
)
/* Populate year table */
INSERT #YEAR_TABLE
SELECT distinct YEAR1 FROM SBM01.dbo.SY40101 ORDER BY YEAR1
/* Create our table of months to UNION to the main accounts */
DECLARE #MONTHS table (
GPACCOUNTNO char(129),
DESCRIPTION char(51),
FISCALYEAR smallint ,
FISCALPERIOD smallint,
FISCALPERIODNAME char(21),
NETCHANGE numeric(19, 5),
PERIODBALANCE numeric(19, 5)
)
/* Here comes the heavy lifting.
We loop over the account numbers and add year and month values.
*/
SET #i = 1
SET #numrows = (SELECT COUNT(*) FROM #ACCT_TABLE)
IF #numrows > 0
WHILE(#i <= (SELECT MAX(idx) FROM #ACCT_TABLE))
BEGIN
/* Get the next account number */
SET #ACCT = (SELECT account FROM #ACCT_TABLE WHERE idx = #i)
SET #c = 1
SET #numyears = (SELECT COUNT(*) FROM #YEAR_TABLE)
WHILE(#c <= (SELECT MAX(idx) FROM #YEAR_TABLE))
BEGIN
SET #y = (SELECT YEAR1 FROM #YEAR_TABLE WHERE idx = #c)
SET #m = '0'
WHILE(#m < '13')
BEGIN
INSERT INTO #MONTHS (GPACCOUNTNO, DESCRIPTION, FISCALPERIOD, FISCALYEAR, FISCALPERIODNAME, NETCHANGE, PERIODBALANCE)
VALUES (#ACCT, NULL, #m, #y, NULL, '0', NULL)
SET #m = #m + 1
END
SET #c = #c + 1
END
SET #i = #i + 1
END
/* We should now have a populated Database */
SELECT Z.GPACCOUNTNO, Z.DESCRIPTION, Z.FISCALYEAR, Z.FISCALPERIOD, Z.FISCALPERIODNAME, Z.NETCHANGE, Z.PERIODBALANCE
FROM ( SELECT RTRIM(B.[ACTNUMST]) AS GPACCOUNTNO,
RTRIM(C.[ACTDESCR]) AS DESCRIPTION,
A.[YEAR1] AS FISCALYEAR,
A.[PERIODID] AS FISCALPERIOD,
E.[PERNAME] AS FISCALPERIODNAME,
ISNULL(A.[PERDBLNC], 0) AS NETCHANGE,
( SELECT ISNULL(SUM(D.[PERDBLNC]), 0)
FROM SBM01.[dbo].[GL10110] D
WHERE D.[ACTINDX] = A.[ACTINDX]
AND D.[YEAR1] = A.[YEAR1]
AND D.[PERIODID] <= A.[PERIODID]
) AS PERIODBALANCE
FROM SBM01.[dbo].[GL10110] A
INNER JOIN SBM01.[dbo].[GL00105] B ON B.[ACTINDX] = A.[ACTINDX]
INNER JOIN SBM01.[dbo].[GL00100] C ON C.[ACTINDX] = A.[ACTINDX]
INNER JOIN SBM01.[dbo].[SY40100] E ON E.[YEAR1] = A.[YEAR1]
AND E.[PERIODID] = A.[PERIODID]
AND E.[SERIES] = 0
UNION ALL
SELECT RTRIM(B.[ACTNUMST]) AS GPACCOUNTNO,
RTRIM(C.[ACTDESCR]) AS DESCRIPTION,
A.[YEAR1] AS FISCALYEAR,
A.[PERIODID] AS FISCALPERIOD,
E.[PERNAME] AS FISCALPERIODNAME,
ISNULL(A.[PERDBLNC], 0) AS NETCHANGE,
( SELECT ISNULL(SUM(D.[PERDBLNC]), 0)
FROM SBM01.[dbo].[GL10111] D
WHERE D.[ACTINDX] = A.[ACTINDX]
AND D.[YEAR1] = A.[YEAR1]
AND D.[PERIODID] <= A.[PERIODID]
) AS PERIODBALANCE
FROM SBM01.[dbo].[GL10111] A
INNER JOIN SBM01.[dbo].[GL00105] B ON B.[ACTINDX] = A.[ACTINDX]
INNER JOIN SBM01.[dbo].[GL00100] C ON C.[ACTINDX] = A.[ACTINDX]
INNER JOIN SBM01.[dbo].[SY40100] E ON E.[YEAR1] = A.[YEAR1]
AND E.[PERIODID] = A.[PERIODID]
AND E.[SERIES] = 0
) Z
RIGHT JOIN #MONTHS M
ON Z.GPACCOUNTNO = M.GPACCOUNTNO
AND Z.FISCALPERIOD = M.FISCALPERIOD
AND Z.FISCALYEAR = M.FISCALYEAR
ORDER BY Z.[GPACCOUNTNO],
M.[FISCALYEAR],
M.[FISCALPERIOD]

Why don't you use the #Months table as the starting point (since it already gives you all the months you need) and fill-in the values from Z if they are available?
SELECT
M.GPACCOUNTNO,
M.DESCRIPTION,
M.FISCALYEAR,
M.FISCALPERIOD,
M.FISCALPERIODNAME,
ISNULL(Z.NETCHANGE, 0) as NETCHANGE
ISNULL(Z.PERIODBALANCE, 0) as PERIODBALANCE
FROM #MONTHS M
LEFT JOIN Z
ON Z.GPACCOUNTNO = M.GPACCOUNTNO
AND Z.FISCALPERIOD = M.FISCALPERIOD
AND Z.FISCALYEAR = M.FISCALYEAR

You can use a SQL case statement to join when null
CREATE TABLE #TMP
(
id int,
[month] datetime
)
INSERT INTO #TMP(id,[month])values(1,GETDATE())
INSERT INTO #TMP(id,[month])values(2,null)
INSERT INTO #TMP(id,[month])values(3,GETDATE())
INSERT INTO #TMP(id,[month])values(4,GETDATE())
CREATE TABLE #TMP2
(
id int,
[month] datetime
)
INSERT INTO #TMP2(id,[month])values(1,GETDATE())
INSERT INTO #TMP2(id,[month])values(2,GETDATE())
INSERT INTO #TMP2(id,[month])values(3,GETDATE())
INSERT INTO #TMP2(id,[month])values(4,GETDATE())
select * from #TMP
select * from #TMP2
SELECT #TMP.[id], case when #TMP.[month] is null then #TMP2.[month] else #TMP.month end
from #tmp
inner join #tmp2 on #tmp.id= #tmp2.id
drop table #tmp,#tmp2

Related

Pagination over join table rows

I have a SQL server request with several tables, for example:
Workorder
WorkorderOccurrence
Schedule
A workorder occurrence is a realisation of a specific schedled workorder
For workorder 1 scheduled every day I have:
Workorder occurrence 1_1 the first day
Workorder occurrence 1_2 the second day
For a workorder 2 scheduled every week I have:
Workorder occurrence 1_7
Workorder occurrence 2_1
Workorder occurence 1_8
And so ...
I have a pagination on the front for an agenda view, but the pagination must be done on workorder and not on the occurrence.
Consequently I would like to return the workorder occurrences (maybe 50, 100, 200,).
but on the 20 workorder request by the pagination. But it seems to eeturn the 20 workorder occurrence with the offset and I don't know how to do this.
Below my attempt:
CREATE FUNCTION [dbo].[FctGetWorkorderAgenda]
(
#SeverityIDsFilter NVARCHAR(MAX) = '',
#Culture NVARCHAR(MAX) = 'FR-fr',
#StartDate DATETIMEOFFSET(7),
#EndDate DATETIMEOFFSET(7),
#PageNumber INT = 0,
#ResultByPage INT = 50
)
RETURNS #resTable TABLE
(
[WorkorderID] INT NOT NULL,
[EndDate] DATETIMEOFFSET(0),
[Name] NVARCHAR(MAX),
[FixedNextDate] DATETIMEOFFSET(0),
[NextDate] DATETIMEOFFSET(0),
[WorkorderStatutType] SMALLINT NOT NULL,
[FrequenceType] SMALLINT NOT NULL,
[DayOfWeek] INT,
[DayOfMonth] INT,
[MonthType] INT,
[DayOfMonthType] INT,
[FrequencyTime] TIME(7) NOT NULL,
[FrequencyOffset] INT,
[VendorName] NVARCHAR(MAX) NOT NULL,
[EquipmentName] NVARCHAR(MAX) NOT NULL,
[OrganizationID] INT NOT NULL,
[WorkorderSeverity] INT NOT NULL,
[FullCount] INT NOT NULL
)
AS
BEGIN
INSERT INTO #resTableBooking (
WO.WorkorderID,
WO.EndDate,
WO.Name,
WOO.FixedNextDate,
WOO.NextDate,
WOO.WorkorderStatutType,
S.FrequenceType,
S.DayOfWeek,
S.DayOfMonth,
S.MonthType,
S.DayOfMonthType,
[FrequencyTime],
S.FrequencyOffset,
[EquipmentName],
[WorkorderSeverity],
[FullCount])
SELECT
WorkorderID,
EndDate,
Name,
FixedNextDate,
NextDate,
WorkorderStatutType,
FrequenceType,
DayOfWeek,
DayOfMonth,
MonthType,
DayOfMonthType,
FrequencyTime,
FrequencyOffset,
EquipmentName,
WorkorderSeverity,
FullCount
FROM (
SELECT
WO.WorkorderID,
WO.EndDate,
WO.Name,
WOO.FixedNextDate,
WOO.NextDate,
WOO.WorkorderStatutType,
S.FrequenceType,
S.DayOfWeek,
S.DayOfMonth,
S.MonthType,
S.DayOfMonthType,
S.Time AS FrequencyTime,
S.FrequencyOffset,
E.Name AS EquipmentName,
(
CASE
WHEN (WO.EndDate IS NOT NULL AND (WO.EndDate <= WO.CreatedDate OR WO.NextDate >= WO.EndDate))
THEN -5 -- WorkorderSeverity.Closed
WHEN (WO.NextDate <= WO.CreatedDate)
THEN -4 -- WorkorderSeverity.DeadlineLate
WHEN (S.FrequenceType = 3) -- FrequencyType.EveryMonth
THEN IIF(
DATEADD(day, -7, WO.NextDate) <= WO.CreatedDate,
-3 /* WorkorderSeverity.DeadlineWarning */,
-2 /* WorkorderSeverity.InTime */
)
WHEN (S.FrequenceType = 1 OR S.FrequenceType = 6)
THEN IIF(
DATEADD(month, -1, WO.NextDate) <= WO.CreatedDate,
-3 /* WorkorderSeverity.DeadlineWarning */,
-2 /* WorkorderSeverity.InTime */
)
WHEN (S.FrequenceType = 0) -- FrequencyType.None
THEN CASE
WHEN (WO.NextDate <= WO.CreatedDate) THEN -4 /* WorkorderSeverity.DeadlineLate */
WHEN (DATEADD(day, -3, WO.NextDate) <= WO.CreatedDate) THEN -3
ELSE -2
END
ELSE -2
END
) AS WorkorderSeverity,
COUNT(WO.WorkorderID) OVER() FullCount
FROM [dbo].[WorkorderOccurrence] WOO WITH(NOLOCK)
JOIN [dbo].[Workorder] WO WITH(NOLOCK) ON WO.WorkorderID = WOO.WorkorderID
JOIN [dbo].[Schedule] S WITH(NOLOCK) ON S.ScheduleID = WO.WorkorderScheduleID
JOIN [dbo].[Equipment] E WITH(NOLOCK) ON E.EquipmentID = WO.EquipmentID
LEFT JOIN dbo.Localization l WITH(NOLOCK) ON l.CultureKey = E.CultureKey AND l.CultureName = #culture
WHERE (WOO.FixedNextDate IS NOT NULL AND WOO.FixedNextDate BETWEEN #StartDate AND #EndDate
OR WOO.NextDate IS NOT NULL AND WOO.NextDate BETWEEN #StartDate AND #EndDate)
GROUP BY WO.WorkorderID, WO.EndDate, WO.Name, WO.CreatedDate, WO.NextDate,
WOO.NextDate, WOO.FixedNextDate, WOO.WorkorderOccurrenceID, WOO.WorkorderStatutType,
S.FrequenceType, S.DayOfWeek, S.DayOfMonth, S.MonthType, S.DayOfMonthType, S.Time, S.FrequencyOffset,
E.Name
) AS base
LEFT JOIN
(
SELECT [value]
FROM STRING_SPLIT(#SeverityIDsFilter, ';')
) AS DynamicSeverityFilter ON WorkorderSeverity = DynamicSeverityFilter.[value]
WHERE ((DynamicSeverityFilter.[value] IS NULL AND #SeverityIDsFilter = '') OR DynamicSeverityFilter.[value] IS NOT NULL)
ORDER BY base.WorkorderID, base.NextDate
OFFSET (#PageNumber * #ResultByPage) ROWS
FETCH NEXT #ResultByPage ROWS ONLY
RETURN
END
I think the "easiest" is to make this a two-step solution.
Fetch head data first into a table variable and use the offset thingy.
Join the head data with the row data and select "out" it together.
Simplified version of your function (but i also think you should convert it to regular procedure)
CREATE FUNCTION [dbo].[FctGetWorkorderAgenda]
(
#SeverityIDsFilter NVARCHAR(MAX) = '',
#Culture NVARCHAR(MAX) = 'FR-fr',
#StartDate DATETIMEOFFSET(7),
#EndDate DATETIMEOFFSET(7),
#PageNumber INT = 0,
#ResultByPage INT = 50
)
RETURNS #resTable TABLE
(
[WorkorderID] INT NOT NULL,
...
)
AS
BEGIN
-- Get data by filter
declare #head TABLE (workorderID INT)
insert into #head (workOrderID)
select wo.workorderID
from Workorder wo
... needed joins
where <your filters>
ORDER BY ...
OFFSET (#PageNumber * #ResultByPage) ROWS
FETCH NEXT #ResultByPage ROWS ONLY
-- Return joined data to the client
insert into #resTableBooking (
WO.WorkorderID,
...
)
SELECT WorkorderID
, ...
FROM #head h
inner join rest...
...
ORDER BY ...
RETURN
END

Churn Rate From Contract Start & End Dates

I am trying to calculate the churn rate of customer and all I have to play with is contract start & end dates.
When the date year is 9999 it just means they are still a customer and I would like to consider account only who have a tenure of more than 3 months (as in have been with the company for 3 or more months).
CREATE TABLE #temp
(
ACCOUNT varchar(20)NOT NULL
,CONTRACT_START_DATE DATETIME NOT NULL
,CONTRACT_END_DATE DATETIME NOT NULL
)
;
INSERT INTO #temp
VALUES('64074558792','20160729','20170805');
INSERT INTO #temp
VALUES('54654654664','20160810','20170110');
INSERT INTO #temp
VALUES('21454654764','20160112','20160812');
INSERT INTO #temp
VALUES('21654765134','20160101','20161231');
INSERT INTO #temp
VALUES('13214868794','20160811','99991231');
INSERT INTO #temp
VALUES ('88321546894','20160427','20160627');
SELECT *,
CASE WHEN CONTRACT_END_DATE <> '99991231' THEN DATEDIFF(DAY, CONTRACT_START_DATE,CONTRACT_END_DATE) ELSE null END AS TENURE
FROM #temp
The below will work for a single reporting year. There's a few things it seems like you're trying to get:
-Number of customers who stay longer than x months
-% of customers that stay for more than x months
-% of customers lost during the year
DECLARE #records TABLE
(
ACCOUNT varchar(20)NOT NULL
,CONTRACT_START_DATE DATETIME NOT NULL
,CONTRACT_END_DATE DATETIME NOT NULL
);
DECLARE #ReportingYear INT = 2016;
DECLARE #MinTenureMonths INT = 3;
INSERT INTO #records
VALUES('64074558792','20160729','20170805'),
('54654654664','20160810','20170110'),
('21454654764','20160112','20160812'),
('21654765134','20151011','20161231'),--I changed this one
('13214868794','20160811','99991231'),
('88321546894','20160427','20160627');
SELECT *,
[CustomerGained] = IIF(YEAR(CONTRACT_START_DATE) = #ReportingYear,1,0),
[CustomerLost] = IIF(YEAR(CONTRACT_END_DATE) = #ReportingYear,1,0) ,
[ExistingCustomer] = IIF(CONTRACT_START_DATE < DATEFROMPARTS(#ReportingYear,1,1)
AND CONTRACT_END_DATE > DATEFROMPARTS(#ReportingYear,12,31), 1, 0),
[CurrentCustomer] = IIF(CONTRACT_END_DATE = '99991231 00:00:00.000',1,0),
[MinTenureExceeded] = IIF(DATEDIFF(MONTH, CONTRACT_START_DATE, CONTRACT_END_DATE) >= #MinTenureMonths,1,0)
FROM #records;
With recordCTE AS
(
SELECT
[CustomersGained] = SUM(IIF(YEAR(CONTRACT_START_DATE) = #ReportingYear,1,0)),
[CustomersLost] = SUM(IIF(YEAR(CONTRACT_END_DATE) = #ReportingYear,1,0)),
[MinTenureExceeded] = SUM(IIF(DATEDIFF(MONTH, CONTRACT_START_DATE, CONTRACT_END_DATE) >= #MinTenureMonths,1,0)),
[ExistingCustomers] = SUM(IIF(CONTRACT_START_DATE < DATEFROMPARTS(#ReportingYear,1,1)
AND CONTRACT_END_DATE > DATEFROMPARTS(#ReportingYear,12,31), 1, 0)),
[CurrentCustomer] = SUM(IIF(CONTRACT_END_DATE = '99991231 00:00:00.000',1,0)),
[TotalCustomers] = COUNT(1)
FROM #records
)
SELECT c.CustomersGained,
c.CustomersLost,
c.MinTenureExceeded,
c.ExistingCustomers,
[% Lost] = CAST(((c.CustomersLost * 1.0) / c.TotalCustomers) * 100 AS DECIMAL(14,2)),
[% Gained] = CAST(((c.CustomersGained * 1.0) / c.TotalCustomers) * 100 AS DECIMAL(14,2))
FROM recordCTE c;
You'll need to decide whether you're just looking for a single reporting year, a reporting period, or in total for everything. If you want everything, just do all the calcs using CurrentCustomers instead.

How to calculate no. of days between two datetime column in SQL Server

There are two tables, T1 includes start date column and T2 includes end date column. Both the columns have both date and time.
T1 has all the rows unique while T2 can have multiple rows for same id and in all the row the end date column might be different (each row with different date and time).
I want to calculate the difference (no. of days) between End date and the start date while keeping in mind that we have to only pick the last date which is lying in the End date column.
;WITH MaxEndDate AS
(
SELECT
T2.PrimaryKey,
MaxEndDate = MAX(EndDate)
FROM
T2
GROUP BY
T2.PrimaryKey
)
SELECT
T1.PrimaryKey,
T1.StartDate,
M.MaxEndDate,
AmountDays = DATEDIFF(DAY, T1.StartDate, M.MaxEndDate)
FROM
T1
INNER JOIN MaxEndDate AS M ON T1.PrimaryKey = M.PrimaryKey
I would recommend creating a temporary table using T2 something like
Select Distinct ID
,MAX(ENDDATE) As [ENDDATE]
INTO #TMPTABLE1
then you include this into T1
Select A.ID
,Startdate
,B.ENDDATE
,Datediff(day,A.STARTDATE,B.ENDDATE) as DAYS
From T1 as A inner join
#TEMPTABLE1 as B on A.ID = B.ID
--------get no of days among multiple dates----------
DECLARE #i INT , #numrows INT , #days INT , #Fdate DATETIME , #Tdate DATETIME;
SET
#days = 0;
DECLARE #employee_table TABLE ( idx SMALLINT PRIMARY KEY IDENTITY(1,
1) ,
EmpId INT ,
SinceDate DATETIME ,
TillDate DATETIME );
-- populate employee table INSERT #employee_table
SELECT
EmpId ,
SinceDate ,
TillDate
FROM
T_EmpPosting_PIS
WHERE
EmpId = 18
AND OfficeTypeID = 1
ORDER BY
TransDate;
--SELECT
*
FROM
#employee_table -- enumerate the table
SET
#i = 1;
SET
#numrows = ( SELECT
COUNT(*)
FROM
#employee_table );
IF #numrows > 0 WHILE ( #i <= ( SELECT
MAX(idx)
FROM
#employee_table ) ) BEGIN
SET
#Fdate = ( SELECT
SinceDate
FROM
#employee_table
WHERE
idx = #i );
IF ( #i = #numrows ) BEGIN
SET
#Tdate = GETDATE();
END;
ELSE BEGIN
SET
#Tdate = ( SELECT
TillDate
FROM
#employee_table
WHERE
idx = #i );
END;
SET
#days = ( SELECT
DATEDIFF(DAY,
#Fdate,
#Tdate) ) #days;
SET
#i = #i 1;
END;
SELECT
#days;

How to speed up an insert transaction being repeated over and over

I have created 2 temp tables, #Table1 being the source and #Table2 being the output table. I have to traverse through each row on #Table1 to make the necessary calculations before inserting each row into #Table2 because the calculation is also dependent on previous rows in #Table2.
I have all the rows in the order I want, and have all the calculations working perfectly. The only problem is that when I go through my 30,000 rows of test data, it takes over 30 minutes. Which means when I expand the query to the full scope of over 2,000,000 rows it will take far too long.
Example Tables:
My solution on traversing through each record in #Table1 to come up with #Table2 is provided below.
exec [database_name].dbo.drop_if_exists '#Table2'
create table #Table2 (ID int, Shipment varchar(8), Delivery int, Arrival datetime, ETA datetime, ETA_TimeStamp datetime, Compliant int)
declare #z int
declare #currentShipment varchar(8)
declare #currentStop int
declare #previousID int
declare #previousETA datetime
set #z = 1
while #z <= (Select max(ID) from #Table1)
Begin
Set #currentShipment = (Select Shipment from #Table1 where ID = #z)
Set #currentStop = (Select Delivery from #Table1 where ID = #z)
Set #previousID = (Select max(ID) from #Table2 where Shipment = #currentShipment AND Delivery = #currentStop AND ID < #Z AND Compliant = 1)
Set #previousETA = (Select ETA from #Table2 where ID = #previousID)
if (Select count(Shipment) from #Table2 where Shipment = #currentShipment AND Delivery = #currentStop AND ID < #Z AND Compliant = 1) = 0
BEGIN
insert into #Table2 Select ID
, Shipment
, Delivery
, Arrival
, ETA
, ETA_Timestamp
, Compliant_Prelim as [Compliant]
from #Table1
where ID = #Z
END
if (Select count(Shipment) from #Table2 where Shipment = #currentShipment AND Delivery = #currentStop AND ID < #Z AND Compliant = 1) > 0
BEGIN
insert into #Table2 Select ID
, Shipment
, Delivery
, Arrival
, ETA
, ETA_Timestamp
, case when (Select Compliant_Prelim from #Table1 where ID = #z) = 1
AND ETA_TimeStamp <= dateadd(hh, -1, #previousETA)
then 1
else 0 end as [Compliant]
from #Table1
where ID = #Z
END
Set #z = #z + 1
End
Select * from #Table2
How do I speed up the insert statement given this example?
The performance isn't in the "insert" itself. It is in the queries used to create the data (the select part of the insert). To fix this, consider the following.
Make sure that the id column in #table1 has an index:
create index on #table1(id);
And make sure that #table2(shipment) has an index:
create index on #table2(shipment);

How can I run a query against a series of value pairs and store the results in a temporary table?

Assume that I have an array of values:
(A1,a1, A2,a2, A3,a3, A4,a4....., An,an)
How should I automate and run the below TSQL query against the (A1,a1..... ,An,an) pairs
SELECT COUNT (1)
FROM food
WHERE calories = Ai AND ingredient = ai --i = {1..n}
So that each count obtained by (Ai,ai) {i=1..n} will be stored in a temporary table?
Thanks
Insert the values in your array into a temp table (I'm going to use the same one for the results later):
create table #pairs (
calories varchar(50),
ingredient varchar(50),
count int
)
Then, we can get our result in one step:
UPDATE p
SET count = x.count
FROM #pairs p inner join
( SELECT f.calories, f.ingredient, COUNT(*) as count
FROM food f inner join
#pairs p ON f.calories = p.calories and f.ingredient = p.ingredient
GROUP BY f.calories, f.ingredient
) x ON p.calories = x.calories and p.ingredient = x.ingredient
select * from #pairs
You can do it with dynamix SQL, something like this:
declare #count int, #limit int
select #count = 0, #limit = 5 -- limit is n
declare #sqlcmd varchar(300)
-- table
create table #result (
combination varchar(10),
total int
)
while #count < #limit
begin
select #sqlcmd = 'insert into #results select distinct "(" + ingredient + "," + calories + ")", count(*) from food where calories = A' + convert(varchar, #count) + ' and ingredient = a' + convert(varchar, #count)
exec(#sqlcmd)
select #count = #count + 1
end