Slow stored procedure - sql

I currently have a stored procedure that copies content from one table to another.
However when it is trying to only insert 27 new rows it continues on for over 12 minutes (after which point I stopped it) it said Affected 27 rows 4 times, however changes were not made.
Can you spot any reason the following SP would be slow?
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER Procedure [dbo].[sp_CopyCompanyContent]
(
#intCopyFromCompanyID Int,
#intNewCompanyID Int
)
As
Begin
/*
RaisError If any of Odl/New Company ID's are 0
*/
If (#intCopyFromCompanyID = 0 Or #intNewCompanyID = 0)
Begin
RaisError('New Company ID or Old Company ID can not be 0', 16, 1)
Return
End
/*
Create Temp Table For the Content Sections
*/
If Object_ID('tempdb..#ContentSections') IS Not Null
Begin
Drop Table dbo.#ContentSections
End
/*
Have to get all the existing data for the Old company we are copying from.
Have to also add the Max(ContentSectionID) From ContentSection. Max(ContentSectionID) +
The Identity (Added further down due to laziness) will be our seed for the ContentID
*/
Select CS.ContentID,
CS.SectionID,
CS.MenuOrder,
#intNewCompanyID NewCompanyID,
CS.CompanyID OldCompanyID,
CS.SubMenu,
CS.Link,
CS.HeaderMenu,
CS.ParentContentID,
CRS.*
Into dbo.#ContentSections
From dbo.Company COMP
Join dbo.ContentSection CS
On COMP.Company_id = CS.CompanyID
Join dbo.Content CONT
On CONT.ContentID = CS.ContentID
Cross Join (
Select MAx(ContentSectionID) MaxContentSectionID
From dbo.ContentSection CONT
) crs
Where COMP.Company_id = #intCopyFromCompanyID
Order By COMP.Company_id
/*
We now need to create a table for the existing content for the old company.
Also have to create the seed. Same principle as above.
*/
If Object_ID('tempdb..#Content') IS Not Null
Begin
Drop Table dbo.#Content
End
Select CONT.*,
CRS.*
Into dbo.#Content
From dbo.Company COMP
Join dbo.ContentSection CS
On COMP.Company_id = CS.CompanyID
Join dbo.Content CONT
On CONT.ContentID = CS.ContentID
Cross Join (
Select MAx(ContentID) MaxContentID
From dbo.Content CONT
) crs
Where COMP.Company_id = #intCopyFromCompanyID
Order By COMP.Company_id
/*
Add Identity to each of the tables we have created above. The ID fields will add to
the Max of each table to mimic what the future seeds will be.
*/
exec('Alter table #ContentSections Add ID Int Identity(1,1)')
exec('Alter table #Content Add ID Int Identity(1,1)')
/*
Add content data from the temp table.
*/
Insert Into dbo.Content
(
Title,
Content
)
Select Title,
Content
From dbo.#Content
/*
Have to the Content table up to the content sections table
as this contains what ID has been add to the Content Table.
*/
Insert Into dbo.ContentSection
(
ContentID,
SectionID,
MenuOrder,
CompanyID,
SubMenu,
Link,
HeaderMenu,
ParentContentID
)
Select C.MaxContentID + C.ID,
CS.SectionID,
CS.MenuOrder,
CS.NewCompanyID,
CS.Submenu,
CS.Link,
CS.HEaderMEnu,
CS.ParentContentID
From dbo.#Content C
Join dbo.#ContentSections CS
On C.ID = CS.ID
End

First thing to do is check the query plan for the selects since cross joins are dangerous beasts, if i'm not reading it wrong you'd display the same value in CRS.* in every record right?
If so, make that query before the select and stored the result in a variable and display it in the select, something like this.
DECLATE #maxValue INTEGER
Select #maxValue=MAX(ContentID) MaxContentID
From dbo.Content CONT
Select CONT.*,
#maxValue as MaxContentID
Into dbo.#Content
From dbo.Company COMP
Join dbo.ContentSection CS
On COMP.Company_id = CS.CompanyID
Join dbo.Content CONT
On CONT.ContentID = CS.ContentID
Where COMP.Company_id = #intCopyFromCompanyID
Order By COMP.Company_id

It is probably because of the identity (it is 2 times from the 4 times*27 rows)
exec('Alter table #ContentSections Add ID Int Identity(1,1)')
exec('Alter table #Content Add ID Int Identity(1,1)')
Instead, if you don't want to create the table, try to use ROW_NUMBER() OVER()... clause as ID, and then you don't need to create the identity later.
And as I see, you don't even need to use the Temp Tables, because then you can simply use the two select as INSERT INTO .... SELECT ... With the ROW_NUMBER().
It seems you don't make any changes on the Temp Tables, so you probably don't need them. (Only if you want to use them out of the SP's scope)

Related

Duplicate Values in Query

Novice SQL user here - I am trying to determine the delivery date (de_arrdate) for an order based on event data from the events table. A shipment can have multiple events, shipments usually have 4 events so the events table will return data based on shipment ID for all 4 events. Because of this, my total $$$ is overstated. How can I return only the largest value of the shipment sequence which would essentially be the final event date? My query is below. I've also attached a sample of the current output.
select dba.disp_ship.ds_id, dba.disp_ship.ds_bill_charge,
dba.disp_ship.ds_status, dba.disp_ship.ds_ship_type,
dba.disp_events.de_site, dba.disp_events.de_arrdate,
dba.disp_events.de_shipment_id, dba.disp_events.de_ship_seq
from dba.disp_ship
inner join dba.disp_events on dba.disp_ship.ds_id = dba.disp_events.de_shipment_id
Not sure which RDBMS you are using nor the version, but if I understood correctly, you only want the amount stated in the last event of the sequence, right?
In this case, you already have the order of the events in the de_ship_seq column, so all you need to do is:
with last_event as (
select
de.de_arrdate,
de.de_shipment_id,
max(de.de_ship_seq)
from dba.disp_events as de
group by 1, 2
)
select
ds.ds_id,
ds.ds_bill_charge,
ds.de_arrdate
from dba.disp_ship as ds
join last_event as le on ds.ds_id = le.de_shipment_id
This way, you'll not get duplicity by the table disp_events, since you're only grabbing the maximum of the sequence, which it's supposed to be the last event :)
There are two ways to achieve this scenario.
1. Inner Query
select dba.disp_ship.ds_id, dba.disp_ship.ds_bill_charge,
dba.disp_ship.ds_status, dba.disp_ship.ds_ship_type,
dba.disp_events.de_site, dba.disp_events.de_arrdate,
dba.disp_events.de_shipment_id, dba.disp_events.de_ship_seq
from dba.disp_ship
inner join dba.disp_events on dba.disp_ship.ds_id = dba.disp_events.de_shipment_id,
inner Join (Select a.de_shipment_id as shipid,max(a.de_arrdate) as arrdate
from disp_events a) as t on dba.disp_events.de_shipment_id = t.shipid and dba.disp_events.de_arrdate = t.arrdate
2. Procedure
//Datatype for the Temporary tables is an assumption. Replace with your data type.
begin
declare local temporary table tbl1(
ds_id numeric(10),
ds_bill_charge numeric(14,2),
ds_status int,
ds_ship_type int,
de_site char(20),
de_arrdate date,
de_shipment_id numeric(10),
de_ship_seq numeric(10)
)on commit preserve rows;
declare local temporary table tbl1(
rowid numeric(10);
shipmentid numeric(10)
)on commit preserve rows;
declare #rowcount,#ds_id,i numeric(10);
set i = 1;
insert into tbl1
select dba.disp_ship.ds_id, dba.disp_ship.ds_bill_charge,
dba.disp_ship.ds_status, dba.disp_ship.ds_ship_type,
dba.disp_events.de_site, dba.disp_events.de_arrdate,
dba.disp_events.de_shipment_id, dba.disp_events.de_ship_seq
from dba.disp_ship
inner join dba.disp_events on dba.disp_ship.ds_id = dba.disp_events.de_shipment_id;
insert into tbl2
select number(*), ds_id from(select distinct ds_id from tbl1) a;
select count(*) into #rowcount from tbl2;
while i <= #rowcount Loop
Select ds_id into #ds_id from tbl2 where rowid = i;
delete from tbl1 where ds_id = #ds_id and
de_ship_seq not in(select top 1 de_ship_seq from tbl1 a
where a.ds_id = #ds_id order by de_arrdate desc);
i++;
end Loop;
select * from tbl1;
end
Thank You...

How can I insert into a nested table from the resultset of a select statement?

I have two tables with nested tables of the same type, the type is:
CREATE OR REPLACE TYPE tipo_valor AS OBJECT (
ano DATE, --year
cantidad INTEGER --ammount of exported wine
) ;
CREATE OR REPLACE TYPE hist_export AS OBJECT (
nombre_pais VARCHAR2(100), --name of importer country
cantidad tipo_valor --type referenced above
);
the nested table:
CREATE OR REPLACE TYPE nt_hist_exp IS
TABLE OF hist_export;
And my two tables are:
CREATE TABLE bodega ( --winery
id_bod INTEGER NOT NULL,
exp_an_bod nt_hist_exp ,
)
CREATE TABLE marca ( --wine
id_marca INTEGER NOT NULL,
exp_an_marca nt_hist_exp
)
I have procedure with a select statement that collects the export ammounts from the wine table on a certain year and orders it by country,
PROCEDURE exp_bod ( p_ano DATE,
p_bod_nom VARCHAR2)IS
sumatoria INTEGER;
p_idbod INTEGER;
BEGIN
SELECT id_bod INTO p_idbod
FROM bodega
WHERE nombre_bod = p_bod_nom;
DBMS_OUTPUT.PUT_LINE(to_char(p_idbod));
SELECT nt.nombre_pais,sum(nt.cantidad.cantidad)
INTO sumatoria
FROM bodega b
JOIN presentacion p on p.bodega_fk = b.id_bod
JOIN marca m on m.id_marca = p.marca_fk
CROSS JOIN TABLE(m.exp_an_marca) nt
WHERE b.id_bod = p_idbod
AND nt.cantidad.ano = p_ano
group by nt.nombre_pais
order by nt.nombre_pais;
);
end exp_bod;
the second select in this procedure successfully returns what I need which is a resultset with two columns,one with the country names and the second one with the export ammounts all summed up and ordered, what I want is to insert the rows from that resultset into the nested table in the winery table including the year which is received as an argument by the function
You could use insert as select, creating an instance of your object type as part of the query:
INSERT INTO TABLE (SELECT exp_an_bod FROM bodega b WHERE b.nombre_bod = p_bod_nom)
SELECT hist_export(nt.nombre_pais, tipo_valor(nt.cantidad.ano, sum(nt.cantidad.cantidad)))
FROM bodega b
JOIN presentacion p on p.bodega_fk = b.id_bod
JOIN marca m on m.id_marca = p.marca_fk
CROSS JOIN TABLE(m.exp_an_marca) nt
WHERE b.nombre_bod = p_bod_nom
AND nt.cantidad.ano = p_ano
GROUP BY nt.nombre_pais, nt.cantidad.ano;
I'm assuming nombre_bod is a column on bodega, though you haven't shown that in the table definition, which means you don't really need a separate look-up for that.
This also assumes that exp_an_bod is not null; it can be empty though. It also doesn't make any allowance for an existing row for the country, but it's not very clear from your data model whether than can exist or what should happen if it does. You can update en existing entry using the same mechanism though, as long as you can identify it.
You can do it in PL/SQL like this:
declare
hist_exp nt_hist_exp;
begin
select exp_an_bod
into hist_exp
from bodega
where id_bod = 123;
hist_exp.extend;
hist_exp(hist_exp.LAST) := hist_export('xyz', 456);
update bodega
set exp_an_bod = hist_exp
where id_bod = 123;
end;
If you like to UPDATE rather then INSERT you can also use
UPDATE (select nombre_pais, cantida, id_bod FROM bodega CROSS JOIN TABLE(exp_an_bod))
SET nombre_pais = 'abc'
WHERE id_bod = 123
and cantida = 456;
You may also try
INSERT INTO (select nombre_pais, cantida, id_bod FROM bodega CROSS JOIN TABLE(exp_an_bod)) ...
but I don't think this is possible - I never tried.

Sql Query with Temp tables in Visual Studio 2010 data grid

I apologize up front if this has been answered, i read several other posts and didn't see a clear answer to my question. I am a beginner at VS2010. Basically i have the below query and i want it to display in the data grid view when i run my program.
I can use VS2010 to join two actual tables but as you can see below the temp tables are very important.
IF OBJECT_ID('tempdb..#tempbatch') IS NOT NULL DROP TABLE #tempbatch
IF OBJECT_ID('tempdb..#tempbatch2') IS NOT NULL DROP TABLE #tempbatch2
IF OBJECT_ID('tempdb..#tempbatch1') IS NOT NULL DROP TABLE #tempbatch1
IF OBJECT_ID('tempdb..#tempbatch3') IS NOT NULL DROP TABLE #tempbatch3
IF OBJECT_ID('tempdb..#tempbatch4') IS NOT NULL DROP TABLE #tempbatch4
IF OBJECT_ID('tempdb..#tempbatch5') IS NOT NULL DROP TABLE #tempbatch5
IF OBJECT_ID('tempdb..#tempbatch6') IS NOT NULL DROP TABLE #tempbatch6
IF OBJECT_ID('tempdb..#tempbatch7') IS NOT NULL DROP TABLE #tempbatch7
IF OBJECT_ID('tempdb..#tempbatch8') IS NOT NULL DROP TABLE #tempbatch8
IF OBJECT_ID('tempdb..#tempbatch9') IS NOT NULL DROP TABLE #tempbatch9
IF OBJECT_ID('tempdb..#tempbatch10') IS NOT NULL DROP TABLE #tempbatch10
create table #tempbatch (rowid bigint primary key identity(1,1), shipmentno varchar(64))
insert into #tempbatch select * from #unitnames
select distinct b.dcsID, a.BoxType, b.BoxNO, b.shipmentno, b.PaletteWithinShipment into #tempbatch1 from #tempbatch c
join dva..Boxmapping as a
on c.shipmentno = a.shipmentno
join dva..Boxmapping as b
on a.boxno = b.BoxNO
--where b.shipmentno = '#rmn'
group by b.dcsID, a.BoxType, b.BoxNO, b.shipmentno, b.PaletteWithinShipment
order by b.PaletteWithinShipment, b.BoxNO
--select dcsid,boxtype,boxno,shipmentno from #tempbatch1
select distinct a.dcsid,b.dcsid as manifestDCS,b.rmn into #tempbatch3 from #tempbatch1 a
left outer join dva..manifestDCS b
on a.dcsid = b.dcsid
select distinct b.dcsid,a.rmn into #tempbatch5 from #tempbatch3 a
left outer join dva..manifestdcs b
on a.rmn = b.rmn
select b.dcsid as deliverexDCSID,a.dcsid,a.rmn,pbatch into #tempbatch4 from #tempbatch5 a
left outer join #tempbatch1 b
on a.dcsid = b.dcsid
join dva..document c
on a.dcsid = c.dcsid
where a.dcsid not in (select dcsid from dva..document where ftpstime is null) and a.dcsid not in (select dcsid from dva..boxmapping)
delete from #tempbatch4 where deliverexdcsid is not null
----- ******************************** START OF SECOND QUERY *********************************-------------
select * into #tempbatch6 from dva..Boxmapping
select distinct c.rmn,c.dcsid,b.dcsid as BoxDCSID,a.pbatch into #tempbatch8 from #tempbatch4 a
left outer join dva..manifestDCS b
on a.dcsid = b.dcsid
left outer join dva..manifestdcs c
on b.rmn = c.rmn
select distinct c.rmn,c.dcsid as Missing,a.dcsid,d.BoxNO,d.boxtype,e.palette,e.PaletteWithinShipment,e.shipmentno into #tempbatch9 from #tempbatch8 a
left outer join #tempbatch4 c
on a.rmn = c.rmn
left outer join dva..boxmapping d
on b.dcsid = d.dcsid
left outer join dva..boxmapping e
on d.boxno = e.boxno
delete from #tempbatch9 where dcsID is null
delete from #tempbatch9 where boxno is null
delete from #tempbatch9 where palette is null
select distinct rmn,missing,boxno,boxtype,PaletteWithinShipment,shipmentno from #tempbatch9
order by rmn,PaletteWithinShipment
Wrap the whole of your query in a stored procedure, i.e.
CREATE PROCEDURE dbo.MyData
AS
SET NOCOUNT ON;
BEGIN
<insert your SQL here>
END;
Back in Visual Studio you will need to open a connection to your database, then open a command that you will use in conjunction with a data reader. There should be plenty of examples of how to do this, but I will give you a very short sample (sorry it's in C#, I don't touch VB):
using (var con = new SqlConnection("Server=WHATEVERSERVER;Database=WHATEVERDBS;Trusted_Connection=True;"))
{
con.Open();
using (var com = con.CreateCommand())
{
com.CommantText = "EXECUTE <MyDatabase>.dbo.MyData;";
using (var dr = com.ExecuteReader())
{
while (dr.Read())
{
var row = new string[7];
row[0] = dr["rmn"].ToString();
row[1] = dr["missing"].ToString();
etc...
MyDataGrid.Rows.Add(row);
}
}
}
}
Finally, you can just pull back a row count from your data grid, to get the number of rows of data that you want to display in a window.
If you can't create a stored procedure then you could type the entire SQL script into the command text bit, but you would have to be very careful with the carriage returns, spacing, literals, quotes, etc.
Again, apologies that my example code is in C#, I was just wanting to give you a very basic framework, so at the very least you know what to go and type into Google...

How can I perform the Count function with a where clause?

I have my database setup to allow a user to "Like" or "Dislike" a post. If it is liked, the column isliked = true, false otherwise (null if nothing.)
The problem is, I am trying to create a view that shows all Posts, and also shows a column with how many 'likes' and 'dislikes' each post has. Here is my SQL; I'm not sure where to go from here. It's been a while since I've worked with SQL and everything I've tried so far has not given me what I want.
Perhaps my DB isn't setup properly for this. Here is the SQL:
Select trippin.AccountData.username, trippin.PostData.posttext,
trippin.CategoryData.categoryname, Count(trippin.LikesDislikesData.liked)
as TimesLiked from trippin.PostData
inner join trippin.AccountData on trippin.PostData.accountid = trippin.AccountData.id
inner join trippin.CategoryData on trippin.CategoryData.id = trippin.PostData.categoryid
full outer join trippin.LikesDislikesData on trippin.LikesDislikesData.postid =
trippin.PostData.id
full outer join trippin.LikesDislikesData likes2 on trippin.LikesDislikesData.accountid =
trippin.AccountData.id
Group By (trippin.AccountData.username), (trippin.PostData.posttext), (trippin.categorydata.categoryname);
Here's my table setup (I've only included relevant columns):
LikesDislikesData
isliked(bit) || accountid(string) || postid(string
PostData
id(string) || posttext || accountid(string)
AccountData
id(string) || username(string)
CategoryData
categoryname(string)
Problem 1: FULL OUTER JOIN versus LEFT OUTER JOIN. Full outer joins are seldom what you want, it means you want all data specified on the "left" and all data specified on the "right", that are matched and unmatched. What you want is all the PostData on the "left" and any matching Likes data on the "right". If some right hand side rows don't match something on the left, then you don't care about it. Almost always work from left to right and join results that are relevant.
Problem 2: table alias. Where ever you alias a table name - such as Likes2 - then every instance of that table within the query needs to use that alias. Straight after you declare the alias Likes2, your join condition refers back to trippin.LikesDislikesData, which is the first instance of the table. Given the second one in joining on a different field I suspect that the postid and accountid are being matched on the same row, therefore it should be AND together, not a separate table instance. EDIT reading your schema closer, it seems this wouldn't be needed at all.
Problem 3: to solve you Counts problem separate them using CASE statements. Count will add the number of non NULL values returned for each CASE. If the likes.liked = 1, then return 1 otherwise return NULL. The NULL will be returned if the columns contains a 0 or a NULL.
SELECT trippin.PostData.Id, trippin.AccountData.username, trippin.PostData.posttext,
trippin.CategoryData.categoryname,
SUM(CASE WHEN likes.liked = 1 THEN 1 ELSE 0 END) as TimesLiked,
SUM(CASE WHEN likes.liked = 0 THEN 1 ELSE 0 END) as TimesDisLiked
FROM trippin.PostData
INNER JOIN trippin.AccountData ON trippin.PostData.accountid = trippin.AccountData.id
INNER JOIN trippin.CategoryData ON trippin.CategoryData.id = trippin.PostData.categoryid
LEFT OUTER JOIN trippin.LikesDislikesData likes ON likes.postid = trippin.PostData.id
-- remove AND likes.accountid = trippin.AccountData.id
GROUP BY trippin.PostData.Id, (trippin.AccountData.username), (trippin.PostData.posttext), (trippin.categorydata.categoryname);
Then "hide" the PostId column in the User Interface.
Instead of selecting Count(trippin.LikesDislikesData.liked) you could put in a select statement:
Select AccountData.username, PostData.posttext, CategoryData.categoryname,
(select Count(*)
from LikesDislikesData as likes2
where likes2.postid = postdata.id
and likes2.liked = 'like' ) as TimesLiked
from PostData
inner join AccountData on PostData.accountid = AccountData.id
inner join CategoryData on CategoryData.id = PostData.categoryid
USE AdventureWorksDW2008R2
GO
SET NOCOUNT ON
GO
/*
Default
*/
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
GO
BEGIN TRAN
IF OBJECT_ID('tempdb.dbo.#LikesDislikesData') IS NOT NULL
BEGIN
DROP TABLE #LikesDislikesData
END
CREATE TABLE #LikesDislikesData(
isLiked bit
,accountid VARCHAR(50)
,postid VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#PostData') IS NOT NULL
BEGIN
DROP TABLE #PostData
END
CREATE TABLE #PostData(
postid INT IDENTITY(1,1) NOT NULL
,accountid VARCHAR(50)
,posttext VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#AccountData') IS NOT NULL
BEGIN
DROP TABLE #AccountData
END
CREATE TABLE #AccountData(
accountid INT
,username VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#CategoryData') IS NOT NULL
BEGIN
DROP TABLE #CategoryData
END
CREATE TABLE #CategoryData(
categoryname VARCHAR(50)
);
INSERT INTO #AccountData VALUES ('1', 'user1')
INSERT INTO #PostData VALUES('1','this is a post')
INSERT INTO #LikesDislikesData (isLiked ,accountid, postid)
SELECT '1', P.accountid, P.postid
FROM #PostData P
WHERE P.posttext = 'this is a post'
SELECT *
FROM #PostData
SELECT *
FROM #LikesDislikesData
SELECT *
FROM #AccountData
SELECT COUNT(L.isLiked) 'Likes'
,P.posttext
,A.username
FROM #PostData P
JOIN #LikesDislikesData L
ON P.accountid = L.accountid
AND L.IsLiked = 1
JOIN #AccountData A
ON P.accountid = A.accountid
GROUP BY P.posttext, A.username
SELECT X.likes, Y.dislikes
FROM (
(SELECT COUNT(isliked)as 'likes', accountid
FROM #LikesDislikesData
WHERE isLiked = 1
GROUP BY accountid
) X
JOIN
(SELECT COUNT(isliked)as 'dislikes', accountid
FROM #LikesDislikesData
WHERE isLiked = 0
GROUP BY accountid) Y
ON x.accountid = y.accountid)
IF (XACT_STATE() = 1 AND ERROR_STATE() = 0)
BEGIN
COMMIT TRAN
END
ELSE IF (##TRANCOUNT > 0)
BEGIN
ROLLBACK TRAN
END
How do you think about the solution? We create a new table SummaryReport(PostID,AccountID,NumberOfLikedTime,NumberOfDislikedTimes).
An user clicks on LIKE or DISLIKE button we update the table. After that, you can query as you desire. Another advantage, the table can be served reporting purpose.

SQL Server 2005 - Using temporary tables in a multi-user environment

I have a problem with this procedure. It uses a couple of temporary tables which it drops and recreates. This is causing loads of crashes, and I can only presume that conflicts are arising.
ALTER PROCEDURE [dbo].[AdditionalVisits_SelectByOrigID]
(
#orig_job_ID int
)
as
if exists (select * from INFORMATION_SCHEMA.TABLES where TABLE_NAME = 'additionalVisitsPodsCnt')
drop table additionalVisitsPodsCnt;
SELECT CONVERT(bit, COUNT(PODS.podID)) AS cnt, AdditionalVisits.this_job_id, AdditionalVisits.orig_job_id
INTO additionalVisitsPodsCnt
FROM PODS RIGHT OUTER JOIN
AdditionalVisits ON PODS.jobID = AdditionalVisits.this_job_id
GROUP BY AdditionalVisits.this_job_id, AdditionalVisits.orig_job_id
HAVING (AdditionalVisits.orig_job_id = #orig_job_ID)
if exists (select * from INFORMATION_SCHEMA.TABLES where TABLE_NAME = 'additionalVisitsPhotosCnt')
drop table additionalVisitsPhotosCnt;
SELECT CONVERT(bit, COUNT(Photos.photoID)) AS cnt, AdditionalVisits.this_job_id, AdditionalVisits.orig_job_id
INTO additionalVisitsPhotosCnt
FROM Photos RIGHT OUTER JOIN
AdditionalVisits ON Photos.jobID = AdditionalVisits.this_job_id
GROUP BY AdditionalVisits.this_job_id, AdditionalVisits.orig_job_id
HAVING (AdditionalVisits.orig_job_id = #orig_job_ID)
SELECT AdditionalVisits.id, AdditionalVisits.this_job_ID, AdditionalVisits.orig_job_ID, AdditionalVisits.reason, AdditionalVisits.date, ThisJob.Job_Reference_No,
ThisJob.Job_POD_Filename, ThisJob.Job_Photo_Filename, ThisJob.Job_Signed_For_Name, ThisJob.Job_Value, ThisJob.Job_Advance_Payment,
ThisJob.Job_Eoj_Payment, ThisJob.Job_Status, ThisJob.Job_Date_Added, ThisJob.Job_Start_Date, additionalVisitsPhotosCnt.cnt AS Job_Photo_Supplied,
additionalVisitsPodsCnt.cnt AS Job_POD_Supplied
FROM AdditionalVisits INNER JOIN
Jobs AS ThisJob ON AdditionalVisits.this_job_ID = ThisJob.Job_ID INNER JOIN
additionalVisitsPodsCnt ON AdditionalVisits.this_job_ID = additionalVisitsPodsCnt.this_job_id INNER JOIN
additionalVisitsPhotosCnt ON AdditionalVisits.this_job_ID = additionalVisitsPhotosCnt.this_job_id
WHERE (AdditionalVisits.orig_job_ID = #orig_job_ID) AND (ThisJob.Job_Status <> 7)
The errors I get are as follow:
Cannot drop the table 'additionalVisitsPodsCnt', because it does not exist or you do not have permission. There is already an object named 'additionalVisitsPodsCnt' in the database.
or
Invalid object name 'additionalVisitsPhotosCnt'.
These errors are intermittent. Sometimes it just works.
Is there a better way of doing this?
Sure, if this table is only used from this one procedure, use a "real" local temporary table (created in tempdb), by prefixing the table name with #:
SELECT CONVERT(bit, COUNT(PODS.podID)) AS cnt,
AdditionalVisits.this_job_id, AdditionalVisits.orig_job_id
INTO #additionalVisitsPodsCnt
FROM PODS ....
This way it is isolated from all other sessions, even if concurrent calls to this procedure are made by others.
Here is the normal pattern I used for a #temp table. (Notice the "#" prefix).
IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
begin
drop table #TableOne
end
CREATE TABLE #TableOne
(
SurrogateKey int ,
NameOf varchar(12)
)
/*
Do something with temp table
*/
IF OBJECT_ID('tempdb..#TableOne') IS NOT NULL
begin
drop table #TableOne
end
Consider using table variables instead.
This StackOverflow topic explains it better than I would... ;)