sql stored procedure, select into - sql-server

i try to build a store procedure who insert data to a table,
after it run, the table is empty.
this is the code:
CREATE TABLE invoices
(invoiceNo int,
invoiceDate date,
invoiceTotal int,
invoiceType char(1))
alter PROCEDURE Invoices_AGG
#year int
AS
select
(case when MONTH(invoiceDate) >9 then concat('01','/',MONTH(invoiceDate),'/',year(invoiceDate)) else concat('01','/0',MONTH(invoiceDate),'/',year(invoiceDate)) end) as DateID,
SUM(case when invoiceType = 'B' then invoiceTotal else 0 end) as Total_Incomes_TypeB,
SUM(case when invoiceType = 'I' then invoiceTotal else 0 end) as Total_Incomes_TypeI
into FACT_Invoices_AGG
from invoices
where year(invoiceDate)=#year
group by (case when MONTH(invoiceDate) >9 then concat('01','/',MONTH(invoiceDate),'/',year(invoiceDate)) else concat('01','/0',MONTH(invoiceDate),'/',year(invoiceDate)) end);
exec Invoices_AGG 2013
thank you

you haven't specified the table in which you want to insert data and since your table is empty on which you are applying your select query it's returning no result.
If you want to use
into
you should also mention your code for FACT_Invoices_AGG function.

The SELECT INTO statement creates a table and fills it with data. Executing 2 or more times that statement will fail (since the table will be created on the first run and will try to create it again on the second one).
If the table is empty is either because the query returned no results, or the SP failed because of the reason I mentioned before (or even failed while building the results, for example with a bad conversion). When using SELECT INTO, make sure to drop the table IF EXISTS before (if this is what you want).
ALTER PROCEDURE Invoices_AGG
#year int
AS
BEGIN
IF EXISTS( SELECT 'table exists' FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = N'FACT_Invoices_AGG'AND TABLE_SCHEMA = 'dbo')
DROP TABLE dbo.FACT_Invoices_AGG
select
(case when MONTH(invoiceDate) >9 then concat('01','/',MONTH(invoiceDate),'/',year(invoiceDate)) else concat('01','/0',MONTH(invoiceDate),'/',year(invoiceDate)) end) as DateID,
SUM(case when invoiceType = 'B' then invoiceTotal else 0 end) as Total_Incomes_TypeB,
SUM(case when invoiceType = 'I' then invoiceTotal else 0 end) as Total_Incomes_TypeI
into
FACT_Invoices_AGG
from
invoices
where
year(invoiceDate)=#year
group by
(case when MONTH(invoiceDate) >9 then concat('01','/',MONTH(invoiceDate),'/',year(invoiceDate)) else concat('01','/0',MONTH(invoiceDate),'/',year(invoiceDate)) end);
END
GO
Another option would be changing your SELECT INTO for a INSERT INTO (columnNames, ...) SELECT which requires that the table exists beforehand.
Try executing the SELECT without the INTO to see if it doesn't fail while computing the result. If it doesn't then make sure the destination table does not exist before using a SELECT INTO.

Related

How do I loop through a table, search with that data, and then return search criteria and result to new table?

I have a set of records that need to be validated (searched) in a SQL table. I will call these ValData and SearchTable respectively. A colleague created a SQL query in which a record from the ValData can be copied and pasted in to a string variable, and then it is searched in the SearchTable. The best result from the SearchTable is returned. This works very well.
I want to automate this process. I loaded the ValData to SQL in a table like so:
RowID INT, FirstName, LastName, DOB, Date1, Date2, TextDescription.
I want to loop through this set of data, by RowID, and then create a result table that is the ValData joined with the best match from the SearchTable. Again, I already have a query that does that portion. I just need the loop portion, and my SQL skills are virtually non-existent.
Suedo code would be:
DECLARE #SearchID INT = 1
DECLARE #MaxSearchID INT = 15000
DECLARE #FName VARCHAR(50) = ''
DECLARE #FName VARCHAR(50) = ''
etc...
WHILE #SearchID <= #MaxSearchID
BEGIN
SET #FNAME = (SELECT [Fname] FROM ValData WHERE [RowID] = #SearchID)
SET #LNAME = (SELECT [Lname] FROM ValData WHERE [RowID] = #SearchID)
etc...
Do colleague's query, and then insert(?) search criteria joined with the result from the SearchTable in to a temporary result table.
END
SELECT * FROM FinalResultTable;
My biggest lack of knowledge comes in how do I create a temporary result table that is ValData's fields + SearchTable's fields, and during the loop iterations how do I add one row at a time to this temporary result table that includes the ValData joined with the result from the SearchTable?
If it helps, I'm using/wanting to join all fields from ValData and all fields from SearchTable.
Wouldn't this be far easier with a query like this..?
SELECT FNAME,
LNAME
FROM ValData
WHERE (FName = #Fname
OR LName = #Lname)
AND RowID <= #MaxSearchID
ORDER BY RowID ASC;
There is literally no reason to use a WHILE other than to destroy performance of the query.
With a bit more trial and error, I was able to answer what I was looking for (which, at its core, was creating a temp table and then inserting rows in to it).
CREATE TABLE #RESULTTABLE(
[feedname] VARCHAR(100),
...
[SCORE] INT,
[Max Score] INT,
[% Score] FLOAT(4),
[RowID] SMALLINT
)
SET #SearchID = 1
SET #MaxSearchID = (SELECT MAX([RowID]) FROM ValidationData
WHILE #SearchID <= #MaxSearchID
BEGIN
SET #FNAME = (SELECT [Fname] FROM ValidationData WHERE [RowID] = #SearchID)
...
--BEST MATCH QUERY HERE
--Select the "top" best match (order not guaranteed) in to the RESULTTABLE.
INSERT INTO #RESULTTABLE
SELECT TOP 1 *, #SearchID AS RowID
--INTO #RESULTTABLE
FROM #TABLE3
WHERE [% Score] IN (SELECT MAX([% Score]) FROM #TABLE3)
--Drop temp tables that were created/used during best match query.
DROP TABLE #TABLE1
DROP TABLE #TABLE2
DROP TABLE #TABLE3
SET #SearchID = #SearchID + 1
END;
--Join the data that was validated (searched) to the results that were found.
SELECT *
FROM ValidationData vd
LEFT JOIN #RESULTTABLE rt ON rt.[RowID] = vd.[RowID]
ORDER BY vd.[RowID]
DROP TABLE #RESULTTABLE
I know this could be approved by doing a join, probably with the "BEST MATCH QUERY" as an inner query. I am just not that skilled yet. This takes a manual process which took hours upon hours and shortens it to just an hour or so.

Trouble Adding Column with ALTER TABLE ADD Function

Trying to add a column (Total_Parts) with
ALTER TABLE ADD
statement but when I execute the query, it says the column I'm adding is an invalid column name and my column doesn't show up in my table.
I have similar code that is implemented elsewhere and it works so I don't know why it fails in this instance.
I've tried taking out the code that references my column in the select statement so that the column isn't referenced until the ALTER TABLE ADD statement but that didn't work.
DECLARE
#Total_Good_Percent float
SELECT
COUNT(CASE WHEN HMC_Place_Position IS NULL THEN 0 END) AS Parts,
COUNT(*) AS Total_Parts,
COUNT(CASE
WHEN Outfeed_Place_Time IS NOT NULL THEN 1
END) AS Total_Good_Parts, /*Total Good Parts */
(COUNT(Total_Good_Parts)*100 / (Total_Parts))/convert(float,count(*)) AS Total_Good_Percent,
COUNT(CASE
WHEN (Reject_Place_Time IS NOT NULL AND Telesis_Stamp = '') THEN 1
END) AS Total_Rejects, /*Total Rejects */
COUNT(CASE
WHEN (HMC_Place_Position IN (13, 14)) AND (Outfeed_Place_Time IS NOT NULL) THEN 1
END) AS Total_Passed_Remeasures, /*Total Passed Remeasures */
COUNT(CASE
WHEN ((Reject_Place_Time IS NOT NULL) AND (Outfeed_Place_Time IS NULL) AND Infeed_Pick_Time IS NULL) THEN 1
END) AS Total_Failed_Remeasures /*Total Failed Rejects */
FROM PartData_GKN05_H
WHERE Infeed_Pick_Time >= DATEADD(day,-7, GETDATE()) OR (Infeed_Pick_Time is null AND (Reject_Place_Time >= DATEADD(day,-7, GETDATE()) OR Outfeed_Place_Time >= DATEADD(day,-7, GETDATE())))
GROUP BY Total_Good_Parts
ALTER TABLE PartData_GKN05_H Add Total_Passed_Remeasures int
ALTER TABLE PartData_GKN05_H Add Total_Good_Parts int
ALTER TABLE PartData_GKN05_H Add Total_Rejects int
ALTER TABLE PartData_GKN05_H Add Total_Failed_Remeasures int
ALTER TABLE PartData_GKN05_H ADD Total_Parts int
ALTER TABLE PartData_GKN05_H ADD Parts int
ALTER TABLE PartData_GKN05_H ADD Total_Good_Percent float
I also have a COUNT AS statement which I believe should create the column but it doesn't.

SQL Server union temp tables

I have a piece of SQL that takes a parameter, assesses the contents of the parameter and depending on the contents applies different UDF to the input parameter.
the code goes something like this:
declare #order varchar(50) = 's12345..s12347'
if isnull( CHARINDEX('.',#order),0) >0
begin
select n as order_no into #temp
FROM F_GetAllNBetween(#order)
end
else if ( isnull( CHARINDEX(',',#order),0) >0 )
begin
select [value] as order_no into #temp2
FROM dbo.F_SplitList(#order,',')
end
if OBJECT_ID('tempdb..#temp') is not null
select * from #temp where order_no <>''
if OBJECT_ID('tempdb..#temp2') is not null
select * from #temp2 where order_no <>''
what I want to do is, get the output from the above union into another temp table and use it in the where clause of the rest of the code.
I cannot use union as it errors saying a select is expected.
I cannot use cte as I cannot use the check to see if the temp tables are empty
I cannot ignore checking for empty temp tables else it errors saying object does not exist ( if statement only creates one of the two temp tables)
I cannot figure out how to get the output to a different temp table. Any ideas suggestions or better way of doing the same please?
As mentioned in my comment, you can simplify your current code to achieve what you want with a UNION and WHERE clauses to replace the IF statements. e.g.
SELECT order_no
--INTO #someTempTable -- if needed
FROM (
SELECT order_no = n
FROM dbo.F_GetAllNBetween(#order)
WHERE CHARINDEX('.', #order) > 0
UNION ALL
SELECT value
FROM dbo.F_SplitList(#order,',')
WHERE CHARINDEX(',', #order) > 0
) AS T
WHERE order_no <> '';

creating table and using if statement

I have this question which I don't really understand
I need help understanding or answering it
--Create the table on the fly with the condition stated
SELECT
TEAM_NAME,
RACES_COMPETED
INTO [TOP TEAMS]
FROM YourTable
WHERE RACES_COMPETED >= 500 and RACES_COMPETED <= 900
--Store the number of teams in the new table in a variable for ease of use
DECLARE #topTeams INT
SET #topTeams = (SELECT COUNT(*) FROM [TOP TEAMS])
--If there are teams in the table, print the number of teams. If there aren't any, print the other statment
IF #topTeams > 0
BEGIN
SELECT 'NO. OF TOP TEAMS: ' + CAST(#topTeams AS VARCHAR)
END
ELSE
BEGIN
SELECT 'NO TOP TEAMS EXIST'
END
HERE IS THE SAME CODE USING A TEMP TALBE
--Drop the TEMP TABLE if it exists
IF OBJECT_ID('tempdb..#TOP_TEAMS') IS NOT NULL DROP TABLE #TOP_TEAMS
--Create the table on the fly with the condition stated
SELECT
TEAM_NAME,
RACES_COMPETED
INTO #TOP_TEAMS
FROM YourTable
WHERE RACES_COMPETED >= 500 and RACES_COMPETED <= 900
--Store the number of teams in the new table in a variable for ease of use
DECLARE #topTeams INT
SET #topTeams = (SELECT COUNT(*) FROM #TOP_TEAMS)
--If there are teams in the table, print the number of teams. If there aren't any, print the other statment
IF #topTeams > 0
BEGIN
SELECT 'NO. OF TOP TEAMS: ' + CAST(#topTeams AS VARCHAR)
END
ELSE
BEGIN
SELECT 'NO TOP TEAMS EXIST'
END

SQL Server UPDATE with WHERE spanning over 2 tables

I have a SQL Server database and I need to manually do an update query. There for no solutions using any programming language can be used.(stored procedures can be used)
I have 4 tables affected (/used) in the query.
[Orders]
[StatusHistoryForOrder]
[StatusHistory]
[Statuses]
I need to update the field [Orders].[OrderStatusID] which is a foreign key to [Statuses]. (So actually changing the state of the order. The table [StatusHistoryForOrder] is a linking table to [StatusHistory] and only contains 2 colums.
[StatusHistoryForOrder].[OrderId]
[StatusHistoryForOrder].[OrderStatusHistoryid]
Don't say that this is not logically cause I already know that. The company who designed the database is a complete retarded company but the database is now too large to set things straight and there is neither the time or money to do it.
The [StatusHistory] table has multiple columns:
[StatusHistory].[OrderStatusHistoryId]
[StatusHistory].[OrderStatusId]
[StatusHistory].[Date]
[StatusHistory].[Message]
The [StatusHistory].[OrderStatusId] is also a foreign key to [Statuses].
In the update query I need to update the status of the order to status 16. But only on rows that now have status 1 and are older then 60 days. I know I can check the date by using the function
DATEDIFF(DD,[StatusHistory].[Date],GETDATE()) > 60
But how to implement this query if the date field is not in the orders. And to set the new [StatusHistory] a new row has to be made for that table and the [StatusHistoryForOrder] table also needs a new row and the ID of that row needs to be set in the [Orders] table row.
Does anyone know how to do this? I am fairly new to SQL Server (or SQL for that matter) and I have absolutly no clue where to begin.
Conclusion:
I need a stored procedure that first checks every row in [Orders] if the [StatusHistory].[Date] (which is linked to the order using foreign keys) of that order is older that 60. If it is older then a new StatusHistory row must be inserted with the current date and status 16. Then in [StatusHistoryForOrder] a new row must be inserted with the new ID of the statusHistory been set in [StatusHistoryForOrder].[OrderStatusHistoryid] and the order id set in [StatusHistoryForOrder].[OrderId]. And last but not least: The [Orders].[OrderStatusID] also needs to be set to 16.
A select query to select the date and status of the order:
SELECT TOP (100) PERCENT
dbo.Orders.OrderID,
dbo.Statuses.Description AS Status,
dbo.StatusHistory.Date
FROM
dbo.Orders
INNER JOIN
dbo.Statuses
ON
dbo.Orders.OrderStatusID = dbo.Statuses.StatusId
INNER JOIN
dbo.StatusHistoryForOrder
ON
dbo.Orders.OrderID = dbo.StatusHistoryForOrder.OrderId
INNER JOIN
dbo.StatusHistory
ON
dbo.StatusHistoryForOrder.OrderStatusHistoryid = dbo.StatusHistory.OrderStatusHistoryId
WHERE
(dbo.Statuses.StatusId = 1)
AND
(DATEDIFF(DD, dbo.StatusHistory.Date, GETDATE()) > 60)
UPDATE
For #marc_s:
Can anyone help me with that?
Try this CTE (Common Table Expression) to find all those orders - does it work, are the results plausible? (this doesn't update anything just yet - just SELECTing for now):
USE (your database name here)
GO
DECLARE #OrdersToUpdate TABLE (OrderID INT, StatusHistoryID INT, StatusDate DATETIME)
;WITH RelevantOrders AS
(
SELECT
o.OrderId, sh.Date
FROM dbo.Orders o
INNER JOIN dbo.StatusHistoryForOrder ho ON ho.OrderId = o.OrderId
INNER JOIN dbo.StatusHistory sh ON ho.OrderStatusHistoryid = sh.OrderStatusHistoryid
WHERE
sh.Date <= DATEADD(D, -60, GETDATE()) -- older than 60 days back from today
AND o.OrderStatusID = 1 -- status = 1
)
INSERT INTO #OrdersToUpdate(OrderID, StatusDate)
SELECT OrderID, [Date]
FROM RelevantOrders
BEGIN TRANSACTION
BEGIN TRY
DECLARE #OrderIDToInsert INT, -- OrderID to process
#InsertedStatusHistoryID INT -- new ID of the inserted row in StatusHistory
-- grab the first OrderID that needs to be processed
SELECT TOP 1 #OrderIDToInsert = OrderID
FROM #OrdersToUpdate
WHERE StatusHistoryID IS NULL
ORDER BY OrderID
-- as long as there are still more OrderID to be processed ....
WHILE #OrderIDToInsert IS NOT NULL
BEGIN
PRINT 'Now inserting new StatusHistory entry for OrderID = ' + CAST(#OrderIDToInsert AS VARCHAR(10))
INSERT INTO dbo.StatusHistory(OrderStatusID, [Date], [Message])
VALUES(16, GETDATE(), 'Bulk Insert/Update operation') -- enter here whatever you want to store
SELECT #InsertedStatusHistoryID = SCOPE_IDENTITY(); -- grab newly inserted ID
PRINT 'New StatusHistory entry inserted with ID = ' + CAST(#InsertedStatusHistoryID AS VARCHAR(10))
UPDATE #OrdersToUpdate
SET StatusHistoryID = #InsertedStatusHistoryID
WHERE OrderID = #OrderIDToInsert
-- safety - reset #OrderIDToInsert to NULL so that we'll know when we're done
SET #OrderIDToInsert = NULL
-- read next OrderID to be processed
SELECT TOP 1 #OrderIDToInsert = OrderID
FROM #OrdersToUpdate
WHERE StatusHistoryID IS NULL
ORDER BY OrderID
END
-- insert into the StatusHistoryForOrder table
INSERT INTO dbo.StatusHistoryForOrder(OrderID, OrderStatusHistoryID)
SELECT OrderID, StatusHistoryID
FROM #OrdersToUpdate
-- update your Orders to status ID = 16
UPDATE dbo.Orders
SET OrderStatusID = 16
FROM #OrdersToUpdate upd
WHERE dbo.Orders.OrderID = upd.OrderID
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
ROLLBACK TRANSACTION
END CATCH
This CTE basically joins your Orders table to the StatusHistory table (via the intermediate link table) and selects the values you're interested in (hopefully!).
This particular problem seems solvable with set operations only.
DECLARE #Orders TABLE (ID int, rownum int IDENTITY);
DECLARE #StatusHistory TABLE (ID int, rownum int IDENTITY);
/* get the list of orders with expired statuses */
INSERT INTO #Orders (ID)
SELECT o.OrderID
FROM Orders o
INNER JOIN StatusHistoryForOrder shfo ON o.OrderID = shfo.OrderId
INNER JOIN StatusHistory sh ON shfo.OrderStatusHistoryid = sh.OrderStatusHistoryId
GROUP BY o.OrderID
HAVING DATEDIFF(DD, MAX(sh.Date), GETDATE()) > 60
/* add so many new rows to StatusHistory and remember the new IDs */
INSERT INTO StatusHistory (OrderStatusId, Date, Message)
OUTPUT inserted.OrderStatusHistoryId INTO #StatusHistory (ID)
SELECT
16,
GETDATE(),
'Auto-inserted as the previous status has expired'
FROM #Orders
/* join the two temp lists together and add rows to StatusHistoryForOrder */
INSERT INTO StatusHistoryForOrder (OrderId, OrderStatusHistoryid)
SELECT o.ID, sh.ID
FROM #Orders o
INNER JOIN #StatusHistory sh ON o.rownum = sh.rownum
/* finally update the statuses in Orders */
UPDATE Orders
SET OrderStatusID = 16
FROM #Orders o
WHERE Orders.OrderID = o.ID
This should be the body of a single transaction, of course.

Resources