SQL Server 2017 Insert to Temp Table Variable is Very Slow but Not in 2014 - sql-insert

I'm upgrading my test database into 2017 developer edition. Now I have a problem with my table value function. the insert into select performance is very very slow for 4000's insert record.
declare #dateStart date = '4-Jul-2019'
,#dateEnd date = '4-Jul-2019'
declare #ntnOnDate table
(
[NTM ID] char(8)
,[NTM Type] char(3) -- Posible Value: NTM, UPR, SOL
,primary key clustered([NTM ID], [NTM Type])
)
declare #finishedNTM table
(
[NTM ID] char(8)
,[NTM Type] char(3)
,Dept char(3)
,[Model Number] char(4)
,[Shoes Type] int
,[Shoes Version] int
,[Size] varchar(5)
,[Pairs] int not null
--, primary key clustered ([NTM ID], [NTM Type],Dept, [Model Number], [Shoes Type], [Shoes Version], [Size])
)
insert into #ntnOnDate
--- select statement (Only 16 record) --
insert into #finishedNTM (
[NTM ID]
, [NTM Type]
, Dept
, [Model Number]
, [Shoes Type]
, [Shoes Version]
, [Size]
, pairs
)
select
a.[TSW ID] as [NTM ID]
,'NTM' as [NTM Type]
,a.[From Department] as [Dept]
,b.[Model Number]
,b.[Shoes Type]
,b.[Shoes Version]
,b.Size
,sum(b.Pairs) as Pairs
from [TSW Master] a
inner join [TSW Details] b
on a.[TSW ID] = b.[TSW ID]
and a.Issue = b.Issue
and a.[From Department] = b.[From Department]
and a.[To Department] = b.[To Department]
--inner join #ntnOnDate c
-- on a.[TSW ID] = c.[NTM ID]
where a.Executed = 1
and a.Accepted = 1
and a.[From Department] <> '210'
--and c.[NTM Type] = 'NTM'
and a.[TSW ID] in (select x.[NTM ID] from #ntnOnDate x where x.[NTM Type] = 'NTM')
group by
a.[TSW ID]
,a.[From Department]
,b.[Model Number]
,b.[Shoes Type]
,b.[Shoes Version]
,b.Size
The strange thing is when I use "select top 4462" (The record count by the select statement is 4462) with the select statement, the insert will complete in 2 seconds.
Can someone help me? Thanks in advance.
A'an

I found myself a sollution to tweak the insert performance. I Change the insert statement into :
insert #finishedNTM
select
a.[NTM ID]
,'NTM' as [NTM Type]
,b.[From Department] as [Dept]
,b.[Model Number]
,b.[Shoes Type]
,b.[Shoes Version]
,b.Size
,b.Pairs
from #ntnOnDate a
inner join (
select
a.[TSW ID]
,a.[From Department]
,b.[Model Number]
,b.[Shoes Type]
,b.[Shoes Version]
,b.Size
,sum(b.Pairs) as Pairs
from [TSW Master] a
inner join [TSW Details] b
on a.[TSW ID] = b.[TSW ID]
and a.Issue = b.Issue
and a.[From Department] = b.[From Department]
and a.[To Department] = b.[To Department]
where a.Executed = 1
and a.Accepted = 1
and a.[From Department] <> '210'
group by
a.[TSW ID]
,a.[From Department]
,b.[Model Number]
,b.[Shoes Type]
,b.[Shoes Version]
,b.Size
) b
on a.[NTM ID] = b.[TSW ID]
where a.[NTM Type] = 'NTM'
The SUM agregate is moved inside a statement block than I join the block with the other temporary table.
But I still don't know why this problem happened. The query is fine on SQL Server 2014.
Regards
A'an

Related

Is there any way to accomplish this in IBM DB2 enviroment

In DB2 is there a way to basically say:
case when sku (select * from table1 where tb1field = 'SMOMD') then 'True' end
Okay so this is my query so far, I've been going at this for at least a month now so any help would be great.
select tb4.customer, tb4.sku, tb4.qty, tb4.retqty, tb4.stipqty, tb4.lastdate, tb4.firstdate, tb4.stipdate
from(
--Table 4
select tb3.Customer as Customer, tb3.sku as SKU, tb3.qty as Qty, tb3.retqty as RetQty, tb3.stipqty as STIPQty,
case when tb3.lastdate is null then '00/0000' else substr(tb3.lastdate,5,2)||'/'||substr(tb3.lastdate,1,4) end as LastDate,
case when tb3.firstdate is null then '00/0000' else substr(tb3.firstdate,5,2)||'/'||substr(tb3.firstdate,1,4) end as FirstDate,
case when tb3.stipdate is null then '00/0000' else substr(tb3.stipdate,5,2)||'/'||substr(tb3.stipdate,1,4) end as STIPDate
from(
--Table 3
select tb2.Customer as Customer, tb2.SKU as SKU, tb2.Qty as Qty, tb2.RetQty as RetQty, tb2.STIPQty as STIPQty,
max(case when tb2.TranID in ('010','100') then tb2.datenum end) as LastDate,
min(case when tb2.TranID in ('010','100') then tb2.datenum end) as FirstDate,
case when tb2.RC = '4M' then tb2.datenum end as STIPDate
from(
--Table 2
select tb1.Customer as Customer, tb1.SKU as SKU,
sum(case when tb1.TranID in ('010','100') then abs(tb1.OrdNet) else '0' end) as Qty,
sum(case when tb1.TranID = '500' and tb1.rc != '4M' then abs(tb1.OrdNet) else '0' end) as RetQty,
count(case when tb1.rc = '4M' then tb1.sku end) as STIPQty,
tb1.datenum as datenum, tb1.TranID as tranid, tb1.RC as rc
from(
--Table 1
select distinct stkund as Customer, sthptg||space(1)||stmodl||space(1)||stvari||space(1)||stfarb||space(1)||stgroe as SKU,
stvorg as TranID, stggru as RC, stprg09 as PG9, stprg08 as PG8, stperi as datenum, ormne1 as OrdNet
from st_usus.s_stati_pv
join caspdtau.cospf440 on stadrn = jadr40
where trim(stvert) in ('111S','122S')
and sthptg != 'V'
and aktv40 = 'A'
and stprg01 in ('01','04')
and stprg02 = '01'
and stvorg in ('500','010','100')
and stperi >= '20160100'
) as tb1
group by tb1.Customer, tb1.SKU, tb1.datenum, tb1.tranid, tb1.rc
) as tb2
group by tb2.customer, tb2.sku, tb2.qty, tb2.retqty, tb2.stipqty, tb2.tranid, tb2.rc, tb2.datenum
) as tb3
group by tb3.customer, tb3.sku, tb3.qty, tb3.retqty, tb3.stipqty, tb3.lastdate, tb3.firstdate, tb3.stipdate
) as tb4
order by tb4.Customer, tb4.sku
I'm not going to try to decipher exactly what you're trying to do...
Some general advice, rather than using Nested Table Expressions (NTE)
select <..> from (select <...>from mytable)
Consider Common Table Expressions (CTE)
with
table1 as (select <...> from st_usus.s_stati_pv join caspdtau.cospf440 on stadrn = jadr40)
, table2 as (select <...> from table1)
, table3 as (select <...> from table2)
, table4 as (select <....> from table3)
select <...> from table4;
Each CTE (ie. tableX) can refer to a prior CTE or a physical table/view as needed. The final select can refer to one or more CTE's along with one or more physical tables or views.
Nice thing about building with CTE's, is that you can check your results after each step..
with
table1 as (select <...> from st_usus.s_stati_pv join caspdtau.cospf440 on stadrn = jadr40)
select * from table1;

What package is ordered most often at each location?

I have been having trouble finding the result for this problem.
Below are my table structure details:
studios
(
studio_id,
location
)
photo_sessions
(
session_id,
studio_id,
cust_id,
session_length,
session_date
)
customer
(
cust_id,
cus_first,
cus_last,
emailid
)
order
(
order_id,
cust_id,
order_description,
amount
)
package_order
(
package_order_id,
order_id,
package_id,
price,
quantity
)
package
(
package_id,
package_name
)
I would like to find which package is ordered most often at each location.
I tried this query,
SELECT
p.package_name,
s.location,
count(p.package_id)
FROM package p,
package_order po,
order_table o,
customer c,
photo_sessions ps,
studios s
WHERE p.package_id=po.package_id
and po.order_id=o.order_id
and o.cust_id=c.cust_id
and c.cust_id=ps.cust_id
and ps.studio_id=s.studio_id
GROUP BY p.package_name,
s.location
HAVING COUNT (p.package_id)=
(
SELECT MAX(mycount)
FROM (
SELECT package_id, COUNT(package_id) as mycount
FROM package_order
GROUP BY package_id
) as most_order
);
I am not sure it gives the right result. Any help will be appreciated.
You can do this with window functions:
WITH cte as (
SELECT
p.package_name,
s.location,
count(p.package_id) AS mycount,
row_number() over(partition by s.location order by count(p.package_id) desc) AS rn
FROM package p
JOIN package_order po ON p.package_id = po.package_id
JOIN order_table o ON po.order_id = o.order_id
JOIN customer c ON o.cust_id = c.cust_id
JOIN photo_sessions ps ON c.cust_id = ps.cust_id
JOIN studios s ON ps.studio_id = s.studio_id
GROUP BY p.package_name,
s.location)
SELECT * FROM cte
WHERE rn = 1
PS: you use Sql Server 2012 but joining with old style deprecated syntax. It is time to forget about old one.
EDIT:
WITH cte as (
SELECT
p.package_name,
s.location,
count(p.package_id) AS mycount
FROM package p
JOIN package_order po ON p.package_id = po.package_id
JOIN order_table o ON po.order_id = o.order_id
JOIN customer c ON o.cust_id = c.cust_id
JOIN photo_sessions ps ON c.cust_id = ps.cust_id
JOIN studios s ON ps.studio_id = s.studio_id
GROUP BY p.package_name,
s.location)
SELECT * FROM cte c1
CROSS APPLY(SELECT MAX(mycount) mycount FROM cte c2 WHERE c1.location = c2.location) ca
WHERE c1.mycount = ca.mycount

Update multiple rows from select statement

I am trying to assign 'A' to [Student Details].group based on this SELECT statement.
SELECT TOP (10) PERCENT [Person Id], [Given Names], Surname, Gpa, [Location Cd]
FROM [Student Details]
WHERE ([Location Cd] = 'PAR')
ORDER BY Gpa DESC
I can't figure out how to use a SELECT statement in an UPDATE statement.
Can someone please explain how to accomplish this?
I am using ASP .NET and MsSQL Server if it makes a difference.
Thanks
I'm assuming you want to update these records and then return them :
SELECT TOP (10) PERCENT [Person Id], [Given Names], Surname, Gpa, [Location Cd]
INTO #temp
FROM [Student Details]
WHERE ([Location Cd] = 'PAR')
ORDER BY Gpa DESC
update [Student Details] set group='A' where [person id] in(select [person id] from #temp)
select * from #temp
I'm also assuming person id is the PK of student details
Try this using CTE (Common Table Expression):
;WITH CTE AS
(
SELECT TOP 10 PERCENT [Group]
FROM [Student Details]
WHERE ([Location Cd] = 'PAR')
ORDER BY Gpa DESC
)
UPDATE CTE SET [Group] = 'A'
Is this you want?
Update top (10) Percent [Student Details] set [group] = 'A'
where [Location Cd] = 'PAR' AND [group] is null

Qualify clause in Oracle

I'm working in Teradata to Oracle migration project. How can i modify the below query which is using QUALIFY in Teradata.
//QUERY 1
SELECT S.ID as Id,
S.MP_CD as Code,
S.GM_CD as GmCode,
S.GM_MSR_NBR as Mea_Year,
S.STTS_CD as YearCode,
S.TRMNTN_DTM as TerminationDate
FROM PD.RVY S, LOAD_LOG TLL
WHERE S.UPDTD_LOAD = TLL.LOG_KEY AND TLL.BLSH_CD = 'Y' AND S.STTS_CD IN ( 'C', 'P' )
QUALIFY ROW_NUMBER () OVER (PARTITION BY S.GM_CD ,S.MP_CD ,S.GM_MSR_NBR,S.STTS_CD
ORDER BY S.SO_DTM DESC
) = 1;
//Query 2
SELECT SP.ID,
SP.SO_DTM,
SP.TAX_ID,
SP.USER_ID,
SP.FRST_NM,
SP.LAST_NM,
SP.PHONE_NBR,
QSRP.TAX_ID,
QSRP.ROW_ID,
MAX(SP.SO_DTM) OVER (PARTITION BY SP.ID, SP.TAX_ID) MAX_SO_DTM
FROM VOPR_RMSY SP,VOPR_RMSY_SPNS QSRP
WHERE SP.ID =:URVYID AND QSRP.TAX_ID =:RPAXID
AND SP.ID = QSRP.ID AND SP.TAX_ID = QSRP.TAX_ID AND SP.SO_DTM = QSRP.SO_DTM
QUALIFY (SP.SO_DTM=MAX_SO_DTM AND QSRP.SO_DTM = MAX_SO_DTM)
GROUP BY SP.ID,SP.SO_DTM,SP.TAX_ID,SP.USER_ID,SP.FRST_NM,SP.LAST_NM,SP.PHONE_NBR,
QSRP.TAX_ID,QSRP.ROW_ID;
For this tried with HAVING instead of qualify but got an Error:
ORA-00904: "MAX_SO_DTM": invalid identifier
00904. 00000 - "%s: invalid identifier"
Seems like alias used for MAX is not working here....
Any of your help is really appreciated!
EDITED:
SELECT * FROM
(
SP.ID,
SP.SO_DTM,
SP.TAX_ID,
SP.USER_ID,
SP.FRST_NM,
SP.LAST_NM,
SP.PHONE_NBR,
QSRP.TAX_ID,
QSRP.ROW_ID,
MAX(SP.SO_DTM) OVER (PARTITION BY SP.ID, SP.TAX_ID) AS MAX_SO_DTM
FROM VOPR_RMSY SP,VOPR_RMSY_SPNS QSRP
WHERE SP.ID =:URVYID AND QSRP.TAX_ID =:RPAXID AND SP.ID = QSRP.ID AND SP.TAX_ID =
QSRP.TAX_ID AND SP.SO_DTM = QSRP.SO_DTM
GROUP BY SP.ID,SP.SO_DTM,SP.TAX_ID,SP.USER_ID,SP.FRST_NM,SP.LAST_NM,SP.PHONE_NBR,
QSRP.TAX_ID,QSRP.ROW_ID;
)dt WHERE (SP.SO_DTM=MAX_SO_DTM AND QSRP.SO_DTM = MAX_SO_DTM)
i know that i have to use alias dt for outer WHERE instead of SP and QSRP but here MAX_SO_DTM is compared with SO_DTM from two different tables. is there any other way to modify this?
Thanks!
Both QUALIFY and reusing an alias is Teradata specific.
Your try with HAVING is failing, because this is the logical sequence of processing a query:
FROM
WHERE
GROUP BY
HAVING
OLAP-function
QUALIFY -- Teradata specific
SAMPLE or EXPAND ON -- both are Teradata specific
ORDER
To resolve this you have to use a Derived Table/Inline View and move the QUALIFY condition into the outer WHERE.
SELECT *
FROM
(
SELECT S.ID as Id,
S.MP_CD as Code,
S.GM_CD as GmCode,
S.GM_MSR_NBR as Mea_Year,
S.STTS_CD as YearCode,
S.TRMNTN_DTM as TerminationDate,
ROW_NUMBER () OVER (PARTITION BY S.GM_CD ,S.MP_CD ,S.GM_MSR_NBR,S.STTS_CD
ORDER BY S.SO_DTM DESC) AS rn
FROM PD.RVY S, LOAD_LOG TLL
WHERE S.UPDTD_LOAD = TLL.LOG_KEY AND TLL.BLSH_CD = 'Y' AND S.STTS_CD IN ( 'C', 'P' )
) dt
WHERE rn = 1;
The same technique must be used when you want to reuse an alias.
EDIT:
The 2nd query can be rewritten as:
SELECT *
FROM
(
SELECT
SP.ID,
SP.SO_DTM,
SP.TAX_ID,
SP.USER_ID,
SP.FRST_NM,
SP.LAST_NM,
SP.PHONE_NBR,
QSRP.TAX_ID,
QSRP.ROW_ID,
MAX(SP.SO_DTM) OVER (PARTITION BY SP.ID, SP.TAX_ID) AS MAX_SO_DTM
FROM VOPR_RMSY SP,VOPR_RMSY_SPNS QSRP
WHERE SP.ID =:URVYID
AND QSRP.TAX_ID =:RPAXID
AND SP.ID = QSRP.ID
AND SP.TAX_ID = QSRP.TAX_ID
AND SP.SO_DTM = QSRP.SO_DTM
GROUP BY SP.ID,SP.SO_DTM,SP.TAX_ID,SP.USER_ID,SP.FRST_NM,SP.LAST_NM,SP.PHONE_NBR,
QSRP.TAX_ID,QSRP.ROW_ID
)dt
WHERE SO_DTM=MAX_SO_DTM
You don't need to do both comparisons *(SP.SO_DTM=MAX_SO_DTM AND QSRP.SO_DTM = MAX_SO_DTM)*, because they the 2nd is redundant as the tables are joined on *SP.SO_DTM = QSRP.SO_DTM*.
Otherwise you had to add QSRP.SO_DTM to the Derived Table using a different alias (e.g. QSRP_SO_DTM). In the outer level there's no more SP/QSRP but only dt, so it would be:
WHERE (SO_DTM=MAX_SO_DTM AND QSRP_SO_DTM = MAX_SO_DTM)

Converting SQL to LINQ

I have following SQL. I need to convert it to LINQ.
ALTER VIEW [dbo].[vwRptBorrowerAccount]
AS
SELECT dbo.tblAccount.[Creditor Registry ID], dbo.tblAccount.[Account No], dbo.tblAccount.[Date Opened], dbo.tblAccount.[Account Status ID],
dbo.tblAccount.[Date First Reported], dbo.tblAccount.[Credit Limit], dbo.tblAccount.Balance, dbo.tblAccount.[Minimum Installment], dbo.tblAccount.[Account Type],
dbo.tblAccount.Term, dbo.tblAccount.Purpose, dbo.tblAccount.[Account Owner Notes], dbo.tblAccount.[Creditor Notes], dbo.tblAccount.Collateral,
dbo.tblAccount.[Collateral Value], dbo.tblAccount.[Legal Status ID], dbo.tblAccount.[Legal Status Date], dbo.tblAccount.LastUpdatedBy,
dbo.tblAccount.LastUpdated, dbo.tblAccount.[Unique ID], dbo.tblAccount.[Account Status Date], dbo.tblAccount.Payment, dbo.tblAccount.[Payment Date],
dbo.tblAccount.[Balance Date], dbo.tblAccount.[Term Frequency], dbo.tblAccount.[State Change Date],
dbo.fn_GetAccountTypeDescription(dbo.tblAccount.[Account Type]) AS [Account Type Description], dbo.tblBusiness.[Business Name] AS CreditorName,
dbo.tblBusiness.Address AS CreditorAddress, dbo.tblBusiness.City AS CreditorCity, dbo.tblBusiness.State AS CreditorState,
dbo.tblLegalStatus.[Legal Status Description] AS [Legal Status], dbo.tblAccountStatus.[Account Status Description] AS [Account Status],
dbo.tblAccountOwner.[Account Owner Registry ID]
FROM dbo.tblAccount INNER JOIN
dbo.tblAccountOwner ON dbo.tblAccount.[Creditor Registry ID] = dbo.tblAccountOwner.[Creditor Registry ID] AND
dbo.tblAccount.[Account No] = dbo.tblAccountOwner.[Account No] INNER JOIN
dbo.tblBusiness ON dbo.tblAccount.[Creditor Registry ID] = dbo.tblBusiness.[Registry ID] INNER JOIN
dbo.tblAccountStatus ON dbo.tblAccount.[Account Status ID] = dbo.tblAccountStatus.[Account Status ID] INNER JOIN
dbo.tblLegalStatus ON dbo.tblAccount.[Legal Status ID] = dbo.tblLegalStatus.[Legal Status ID]
WHERE (dbo.tblAccount.[Account Type] NOT IN ('CA00', 'CA01', 'CA03', 'CA04', 'CA02', 'PA00', 'PA01', 'PA02', 'PA03', 'PA04'))
[EDITED]
and function detail is:
CREATE FUNCTION [fn_GetAccountTypeDescription]
(
-- Add the parameters for the function here
#accountType varchar(max)
)
RETURNS varchar(max)
with schemabinding
AS
BEGIN
-- Declare the return variable here
DECLARE #Result varchar(max)
-- Add the T-SQL statements to compute the return value here
IF EXISTS(SELECT Abbreviation FROM dbo.tblAccountType WHERE [Account Type Code] = #accountType)
BEGIN
SELECT #Result = Abbreviation FROM dbo.tblAccountType WHERE [Account Type Code] = #accountType
END
ELSE
BEGIN
SELECT #Result = #accountType
END
-- Return the result of the function
RETURN #Result
END
Can you please suggest how to convert it to LINQ ? I dont want to use joins.
I do not think you will be able to do this without joins, whether using LINQ or not.
Additionally, it seems like quite the exercise in futility. What benefit do you expect to gain from the time you invest in this?
Furthermore, you haven't specified what LINQ Provider you intend to use, so as is your question is completely unanswerable (each provider has significant differences in syntax).
Ok, make sure you add tblAccountType to your model and it has an association with tblAccount then do somthing like below.
I'm even less able to test this than you but I would suggest that you have a test database with the same schema and populate it with some dummy data.
String[] excludedCodes = new String[]
{
"CA00",
"CA01",
"CA03",
"CA04",
"CA02",
"PA00",
"PA01",
"PA02",
"PA03",
"PA04"
};
var data = context.tblAccount.Where(a => !excludedCodes.Contains(a.AccountType))
.Select(a => new{
a.Creditor_Registry_ID,
a.Account_No,
a.Date_Opened,
...
Account_Type_Description = a.tblAccountType.Where
(t => t.Account_Type_Code = a.Account_Type).SingleOrDefault()
?? a.Account_Type),
Creditor_Name = a.tblBusiness.Business_Name,
CreditorAddress = a.tblBusiness.Address,
...
Legal_Status = a.tblLegalStatus.Legal_Status_Description,
... etc.
});

Resources