changing temp tables to declaring them - sql

Just a question regards to temp tables and declaring table. If I change the temp tables 'ChangedData' and 'PackageDatatoProcess' to their own variables '#ChangedData' and '#PackageDatatoProcess', can I ask how I am suppose to change the select into statement as I have not quite done this before. Virtually I told that we can declare tables rather than using the select into but just need a bit of help with this:
select distinct * into #PackageDataToProcess from #ChangedData pp
outer apply (
select pk.Reference, pjl.PackageToJournalLinkId, j.CreatedDate, pccl.PackageCostChangeLogId from Jet2Holidays.dbo.Package pk
inner join Jet2Holidays.dbo.PackageToJournalLink pjl on pk.PackageId = pjl.PackageId
inner join Jet2Holidays.dbo.Journal j on pjl.JournalId = j.JournalId
and j.PrincipalName= iif(#AllowNonSupportChanges = 0, 'HolidaysSupport', j.PrincipalName)
inner join Jet2Holidays.dbo.BusinessProcess bp on pjl.BusinessProcessId = bp.BusinessProcessId
and bp.[Description] = iif(#AllowNonSupportChanges = 0, 'CallCentreAction', bp.[Description])
left outer join Jet2Holidays.dbo.PackageCostChangeLog pccl on pccl.PackageToJournalLinkId = pjl.PackageToJournalLinkId
where pk.Reference = pp.PackageReference
and pp.JournalID = pjl.JournalId
) as packageData

First, you declare your variable tables like so:
DECLARE #PackageDataToProcess TABLE
(
Reference UNIQUEIDENTIFIER
, PackageToJournalLinkId INT
, CreatedDate DATETIME
, PackageCostChangeLogId INT
, {other columns here}
)
DECLARE #ChangedData TABLE
(
Reference UNIQUEIDENTIFIER
, PackageToJournalLinkId INT
, CreatedDate DATETIME
, PackageCostChangeLogId INT
, {other columns here}
)
At this point you can populate your #ChangedData table like so:
INSERT #ChangedData ( Reference, PackageToJournalLinkId, CreatedDate, PackageCostChangeLogId, {other columns})
SELECT Reference, PackageToJournalLinkId, CreatedDate, PackageCostChangeLogId, {other columns}
FROM ChangedDataSource -- Table, Procedure, Function
And then you can run your code by substituting #PackageDataToProcess for #PackageDataToProcess. Here it is again with a slight re-write (from the original):
INSERT #PackageDataToProcess
select distinct pp.* from #ChangedData pp
outer apply (
select pk.Reference, pjl.PackageToJournalLinkId, j.CreatedDate, pccl.PackageCostChangeLogId from Jet2Holidays.dbo.Package pk
inner join Jet2Holidays.dbo.PackageToJournalLink pjl on pk.PackageId = pjl.PackageId
inner join Jet2Holidays.dbo.Journal j on pjl.JournalId = j.JournalId
and j.PrincipalName= iif(#AllowNonSupportChanges = 0, 'HolidaysSupport', j.PrincipalName)
inner join Jet2Holidays.dbo.BusinessProcess bp on pjl.BusinessProcessId = bp.BusinessProcessId
and bp.[Description] = iif(#AllowNonSupportChanges = 0, 'CallCentreAction', bp.[Description])
left outer join Jet2Holidays.dbo.PackageCostChangeLog pccl on pccl.PackageToJournalLinkId = pjl.PackageToJournalLinkId
where pk.Reference = pp.PackageReference
and pp.JournalID = pjl.JournalId
) as packageData
Your declared tabled will go out of scope in a similar manner to the way your non-global temporary table do.

Related

Left join with result of COALESCE

SELECT *
FROM TBDA temp
LEFT JOIN (
SELECT
(
COALESCE (
(
SELECT sum_payment
FROM TBDA_REPAYMENT
WHERE isdn = temp.isdn
AND tr_month = temp.tr_month
AND tr_year = temp.tr_year
),
(
SELECT sum_payment
FROM TBDA_PAYNEW
WHERE isdn = temp.isdn
AND tr_month = temp.tr_month
AND tr_year = temp.tr_year
)
)
)
)
TBDA table has isdn,tr_month,tr_year
TBDA_REPAYMENT table has isdn,tr_month,tr_year,sum_payment
TBDA_PAYNEW table has isdn,tr_month,tr_year,sum_payment
Expected result :
A table off all fields of TBDA with sum_payment, look for sum_payment from two tables (TBDA_REPAYMENT & TBDA_PAYNEW) by ISDN (TBDA table) by comparing isdn,tr_month,tr_year, if sum_payment exists in one of two tables (TBDA_REPAYMENT & TBDA_PAYNEW) then add it to the results, otherwise it's null.
I get the error :
[Err] 42000 - [SQL Server]Incorrect syntax near ')'.
SELECT
*
FROM
TBDA temp
Cross Apply ( SELECT COALESCE (
(
SELECT
sum_payment
FROM
TBDA_REPAYMENT
WHERE
isdn = temp.isdn
AND tr_month = temp.tr_month
AND tr_year = temp.tr_year
),
(
SELECT
sum_payment
FROM
TBDA_PAYNEW
WHERE
isdn = temp.isdn
AND tr_month = temp.tr_month
AND tr_year = temp.tr_year
)
) as First_Null_Value
) as value_table
Unless a CROSS JOIN, CROSS APPLY or OUTER APPLY is used, the ON clause is required.
Hence the error.
Although you could still do something like ... LEFT JOIN othertable ON (1=1).
But you could re-write this query using 2 left joins.
select
temp.*,
coalesce(repay.sum_payment, paynew.sum_payment) as value_table
from TBDA temp
left join TBDA_REPAYMENT repay on (repay.isdn = temp.isdn and repay.tr_month = temp.tr_month and repay.tr_year = temp.tr_year)
left join TBDA_PAYNEW paynew on (paynew.isdn = temp.isdn and paynew.tr_month = temp.tr_month and paynew.tr_year = temp.tr_year);
Note that there's an assumption that the tables TBDA_REPAYMENT & TBDA_PAYNEW have a uniqueness on the 3 fields used in the join (isdn, tr_month, tr_year).
Or the OUTER APPLY syntax could be used.
And if there's no uniqueness on (isdn, tr_month, tr_year) then you can use that to SUM the total at the same time.
select
temp.*, repay.sum_payment as repay_sum_payment, paynew.sum_payment as paynew_sum_payment,
coalesce(repay.sum_payment, paynew.sum_payment) as value_table
from TBDA temp
outer apply
(
select nullif(sum(rp.sum_payment),0) as sum_payment
from TBDA_REPAYMENT rp
where rp.isdn = temp.isdn
and rp.tr_month = temp.tr_month
and rp.tr_year = temp.tr_year
) as repay
outer apply
(
select nullif(sum(pn.sum_payment),0) as sum_payment
from TBDA_PAYNEW pn
where pn.isdn = temp.isdn
and pn.tr_month = temp.tr_month
and pn.tr_year = temp.tr_year
) as paynew;
Example Snippet:
declare #TBDA table (isdn int, tr_month int, tr_year int);
declare #TBDA_REPAYMENT table (isdn int, tr_month int, tr_year int, sum_payment int);
declare #TBDA_PAYNEW table (isdn int, tr_month int, tr_year int, sum_payment int);
insert into #TBDA (isdn, tr_month, tr_year) values (1,6,2018),(2,6,2018);
insert into #TBDA_REPAYMENT (isdn, tr_month, tr_year, sum_payment) values (1,6,2018, 100);
insert into #TBDA_PAYNEW (isdn, tr_month, tr_year, sum_payment) values (1,6,2018, 200),(2,6,2018,100),(2,6,2018,200);
--
-- Using left join
--
select
temp.*, repay.sum_payment, paynew.sum_payment,
coalesce(repay.sum_payment, paynew.sum_payment) as value_table
from #TBDA temp
left join #TBDA_REPAYMENT repay on (repay.isdn = temp.isdn and repay.tr_month = temp.tr_month and repay.tr_year = temp.tr_year)
left join #TBDA_PAYNEW paynew on (paynew.isdn = temp.isdn and paynew.tr_month = temp.tr_month and paynew.tr_year = temp.tr_year);
--
-- Using outer apply
--
select
temp.*, repay.sum_payment as repay_sum_payment, paynew.sum_payment as paynew_sum_payment,
coalesce(repay.sum_payment, paynew.sum_payment) as value_table
from #TBDA temp
outer apply
(
select nullif(sum(rp.sum_payment),0) as sum_payment
from #TBDA_REPAYMENT rp
where rp.isdn = temp.isdn
and rp.tr_month = temp.tr_month
and rp.tr_year = temp.tr_year
) as repay
outer apply
(
select nullif(sum(pn.sum_payment),0) as sum_payment
from #TBDA_PAYNEW pn
where pn.isdn = temp.isdn
and pn.tr_month = temp.tr_month
and pn.tr_year = temp.tr_year
) as paynew;
Error is due to not specifying ON condition on LEFT JOIN.
LEFT JOIN without ON will throw an error.
If you don't want to specify any condition, try CROSS JOIN
Just use correlated subqueries:
SELECT t.*,
IFNULL ( (SELECT r.sum_payment
FROM TBDA_REPAYMENT r
WHERE r.isdn = t.isdn AND
r.tr_month = t.tr_month AND
r.tr_year = t.tr_year
),
(SELECT p.sum_payment
FROM TBDA_PAYNEW p
WHERE p.isdn = t.isdn AND
p.tr_month = t.tr_month AND
p.tr_year = t.tr_year
)
)
)
FROM TBDA t;
Although you can use APPLY, the use of SELECT is already insisting that at most one row be returned from the subqueries.
Also note a couple of things. First, I replaced COALESCE() with IFNULL(). Although I much prefer COALESCE() (because it is the standard and more flexible), the code is more efficient with IFNULL(). COALESCE() causes SQL Server to evaluate the first argument twice when it is not NULL.
Second, table aliases and qualified column names should be used everywhere in the query.

Accessing table returning by table-valued function from SP

I have table valued function
ALTER FUNCTION [dbo].[fn_Functiont]()
RETURNS TABLE
AS
RETURN
(
SELECT d.*, b.Name AS Name, ps.Name AS PaymentSystemName, c.UserName AS UserName, c.FirstName AS ClientFirstName, c.LastName AS LastName, c.Number AS DocumentNumber, c.Id
FROM Document AS d
JOIN System AS ps ON d.SystemId = ps.Id
JOIN Client AS c ON c.Id = d.ClientId
LEFT JOIN Shop AS b ON b.Id = d.ShopId
WHERE d.OperationTypeId IN (2, 4, 5) AND c.Type = 1
)
And SP. In that SP i have declared temporary table like this
DECLARE #tempTable AS TABLE
(
.. columns here ...
)
after declaring i just inserting info
INSERT INTO #tempTable
SELECT * FROM [dbo].[fn_Functiont]()
Select #column1,colum2...,from #tempTable
The problem is that i have to declare a lot of columns in #temptable and code looks like ugly.So is there a better way to reading rows in SP from table valued function?
Instead of table Variable #tempTable Use Temp Table and Try This
SELECT * INTO #tempTable FROM [dbo].[fn_Functiont]()

Conversion failed while using ids "where ID in (...)", nvarchar to int

I have a query in MSSQL 2008 like:
IF OBJECT_Id('tempdb..#AccessibleFacilities') IS NOT NULL DROP TABLE #AccessibleFacilities
SELECT u.Userid
, AccesibleFacilityIds = dbo.GetCommaDelimitedString(upf.Facility_Id)
INTO #AccessibleFacilities
FROM Users u
INNER join UserProfileFacilities upf on upf.UserProfile_Id = up.Id
WHERE LOWER(u.Userid) = LOWER(#userId)
GROUP BY u.Userid
This query returns AccessibleFacilityIds like ",1,2,3,4,5,6,". Please note that I am not able to modify GetCommaDelimitedString function.
What I actually need to do is that using those facility ids to reach provs like below:
INSERT INTO #AccessibleProvs
SELECT Userid = #userId
, AccessibleProvIds = dbo.GetCommaDelimitedString(distinct p.Id)
FROM Provs p
inner join ProvFacs pf on p.Id = pf.Provider_Id
WHERE pf.Facility_Id in
(select a.AccesibleFacilityIds from #AccessibleFacilities a)
However, it gives me an error like:
Conversion failed when converting the nvarchar value ',1,2,3,4,5,6,'
to data type int.
I tried removing the comma signs at the start and end like below to fix it, but it did not help:
...
where pf.Facility_Id in (
select SUBSTRING(a.AccesibleFacilityIds,2,LEN(a.AccesibleFacilityIds)-2)
from #AccessibleFacilities a
)
Any advice would be appreciated. Thanks.
Instead of converting Facility_Id into a comma delimited string, why not keep it as a usable column in your temp table?
if object_Id('tempdb..#AccessibleFacilities') is not null drop table #AccessibleFacilities;
select
u.UserId
, upf.Facility_Id
into #AccessibleFacilities
from Users u
inner join UserProfileFacilities upf
on upf.UserProfile_Id = up.Id
Then use it as you did with in() or with exists():
insert into #AccessibleProvs
select
UserId = #userId
, AccessibleProvIds = dbo.GetCommaDelimitedString(distinct p.Id)
from Provs p
inner join ProvFacs pf
on p.Id = pf.Provider_Id
where exists (
select 1
from #AccessibleFacilities a
where a.Facility_Id = pf.Facility_Id
--and a.UserId = #UserId -- Do you need to check Facility_Id by User?
)
If you have the value for #UserId in the beginning, you could limit your temp table usage to just the user you need. Hopefully this code is not meant for use in some sort of cursor or other loop.

Query, subquery and using as variables from subquery

Is it not possible to use the "as [item] and then use the item variable in the query.
For example:
select c.category as [category],c.orderby as [CatOrder], m.masterno, m.master
,-- select OUT (select count(*) from rentalitem ri with (nolock),
rentalitemstatus ris with (nolock),
rentalstatus rs with (nolock)
where ri.rentalitemid = ris.rentalitemid
and ris.rentalstatusid = rs.rentalstatusid
and ri.masterid = m.masterid
and rs.statustype in ('OUT', 'INTRANSIT', 'ONTRUCK')) as [qtyout]
,-- select OWNED owned=
(select top 1 mwq.qty
from masterwhqty mwq
where mwq.masterid = m.masterid)
, -([owned]-[qtyout]) as [Variance]
from master m
inner join category c on c.categoryid=m.categoryid and c.categoryid=#category
inner join inventorydepartment d on c.inventorydepartment=#department
I cannot seem to use qtyout or owned when calculating variance. How can I do that?
You can also use a table variable and then reference that table variable like you are trying to do above....here's an example from MSDN
USE AdventureWorks2012;
GO
DECLARE #MyTableVar table(
EmpID int NOT NULL,
OldVacationHours int,
NewVacationHours int,
ModifiedDate datetime);
UPDATE TOP (10) HumanResources.Employee
SET VacationHours = VacationHours * 1.25,
ModifiedDate = GETDATE()
OUTPUT inserted.BusinessEntityID,
deleted.VacationHours,
inserted.VacationHours,
inserted.ModifiedDate
INTO #MyTableVar;
--Display the result set of the table variable.
SELECT EmpID, OldVacationHours, NewVacationHours, ModifiedDate
FROM #MyTableVar;
GO
--Display the result set of the table.
SELECT TOP (10) BusinessEntityID, VacationHours, ModifiedDate
FROM HumanResources.Employee;
GO
need to move your calculated fields into a subquery, and then use them by their alias in the outer query.
select subquery.*, -([owned]-[qtyout]) as [Variance]
from
(
select c.category as [category],c.orderby as [CatOrder], m.masterno, m.master
,-- select OUT (select count(*) from rentalitem ri with (nolock),
rentalitemstatus ris with (nolock),
rentalstatus rs with (nolock)
where ri.rentalitemid = ris.rentalitemid
and ris.rentalstatusid = rs.rentalstatusid
and ri.masterid = m.masterid
and rs.statustype in ('OUT', 'INTRANSIT', 'ONTRUCK')) as [qtyout]
,-- select OWNED owned=
(select top 1 mwq.qty
from masterwhqty mwq
where mwq.masterid = m.masterid) as [owned]
from master m
inner join category c on c.categoryid=m.categoryid and c.categoryid=#category
inner join inventorydepartment d on c.inventorydepartment=#department
) as subquery
YOu need to use a subquery:
select t.*,
([owned]-[qtyout]) as [Variance]
from (<something like your query here
) t
You query, even without the comments, doesn't quite make sense (select OUT (select . . . for isntance). But, the answer to your question is to define the base variables in a subquery or CTE and then subsequently use them.
And, you are calling the difference "variance". Just so you know, you are redefining the statistical meaning of the term (http://en.wikipedia.org/wiki/Variance), which is based on the squares of the differences.

How to delete with these conditions?

How can I delete rows which meet several conditions from a table without primary key? (actually the primary key is formed by every column)
After so many tries I have a code that first creates a temporary table where it inserts the rows I want to delete and finally I try to delete the rows from original table which meet the conditions comparing to temporary table.
But it gives me the error about cannot linking the several parts identifier #temp.idCarga
Maybe it's easy but I have been trying so much time and I cannot focus properly.
CREATE TABLE #TEMP
(
CC int,
idCarga int,
Tipo nvarchar(50),
Importe float,
Bloque nvarchar(50),
idsistema int
)
INSERT INTO #TEMP(CC,idCarga,Importe,Bloque,Tipo,IdSistema)
select distinct CI.CC,CI.idCarga,CI.Importe,CI.Bloque,CI.Tipo,CI.idSistema
from CONT_INGRESOS_InformeMayor CI
INNER JOIN
(
SELECT idCarga,CC,Bloque,Importe,TIpo
FROM CONT_INGRESOS_InformeMayor
) CI2
ON CI.CC = CI2.CC
AND CI.Bloque = CI2.Bloque
AND CI.TIpo <> CI2.Tipo
WHERE CI.idCarga = #idCarga
AND CI2.idCarga = #idCarga
AND CI.Importe = 0
DELETE
FROM CONT_INGRESOS_InformeMayor
WHERE idCarga = #temp.idCarga
AND tipo = #temp.tipo
AND importe = #temp.importe
and bloque = #temp.bloque
You missed a join on your DELETE. Try this:
DELETE _d
FROM CONT_INGRESOS_InformeMayor AS _d
INNER JOIN #temp AS _t
ON _d.idCarga = _t.idCarga
AND _d.tipo = _t.tipo
AND _d.importe = _t.importe
AND _d.bloque = _t.bloque
Your DELETE is missing a JOIN to your #temp table
DELETE t1
FROM CONT_INGRESOS_InformeMayor t1
INNER JOIN #temp t
ON t1.idCarga = t.idCarga
AND t1.tipo = t.tipo
AND t1.importe = t.importe
and t1.bloque = t.bloque
On the other hand, you could try deleting the rows without involving a temporary table:
DELETE FROM CI
from CONT_INGRESOS_InformeMayor CI
INNER JOIN
(
SELECT idCarga,CC,Bloque,Importe,TIpo
FROM CONT_INGRESOS_InformeMayor
) CI2
ON CI.CC = CI2.CC
AND CI.Bloque = CI2.Bloque
AND CI.TIpo <> CI2.Tipo
WHERE CI.idCarga = #idCarga
AND CI2.idCarga = #idCarga
AND CI.Importe = 0