How to loop statements in SQL Server - sql

I am new to SQL Server, I am trying to do something as follows.
Sample code :
SELECT ITEM_ID
FROM 'TABLE_NAME_1'
WHERE ITEM_STATUS = 'ACTIVE'
SET #ITEM_PRICE = (SELECT PRICE
FROM 'TABLE_NAME_2'
WHERE 'PRODUCT_ID' = 'ITEM_ID')
INSERT INTO 'TABLE_NAME_3' (ITEM_ID, PRICE)
VALUES (#ITEM_ID, #ITEM_PRICE)
The first statement will return multiple rows of ITEM_ID
By using the ITEM_ID I need to select the ITEM_PRICE from another table using the second statement
By using the third statement, I need to insert the data into the third table
Here the first statement returns only one ITEM_ID, then everything is easy to do. I f it returns multiple rows how can I do all these processes for all the ITEM_ID which has returned by the first statement?
Actually, If the first statement returns 5 rows I need to loop 5 times.
Is it possible in SQL Server, if yes, please help me to do this

Question would be why not use a straight SQL
INSERT
INTO 'TABLE_NAME_3'
(ITEM_ID
,PRICE
)
SELECT ITEM_ID,ITEM_PRICE
FROM 'TABLE_NAME_1' A
JOIN 'TABLE_NAME_2' B
ON A.ITEM_ID=B.PRODUCT_ID
WHERE A.ITEM_STATUS = 'ACTIVE'

based on your question i have created sample code you can use only one query to insert multiple data if you want to insert common data between table 1 and table 2 then use inner join or left join will be fine.
Code
INSERT INTO 'TABLE_NAME_3' (ITEM_ID,PRICE)
SELECT T1.ITEM_ID , T2.PRICE
FROM 'TABLE_NAME_1' AS T1
INNER JOIN 'TABLE_NAME_2' AS T2 ON T2.PRODUCT_ID = T1.ITEM_ID
WHERE T1.ITEM_STATUS = 'ACTIVE'

Related

Update multiple Columns from multiple tables from the result of Nested SQL Query

I have this query up and running and it gives the absolute correct result. I have 4 tables in total. Table1 , Table2 , Table3 and Table4. The resultant query gives the result by joining 3 different tables.
Now the problem is that I have to 'update' 1 column PER row from each table. I am unable to dig the solution. I'm stuck from 2 days on the same problem, any help would be deeply appreciable :)
SELECT TempID,
custom,
STATE,
orgUnit,
displayName ,
stateCust ,
consumer.bol_is_active AS stateConsumer
FROM
(SELECT TempID,
custom,
STATE,
cust.id_orgunit AS orgUnit,
cust.str_display_name AS displayName,
cust.bol_is_active AS stateCust
FROM
(SELECT DISTINCT CA.ID_CUSTOMER AS TempID ,
ca.str_value AS custom,
ci.bol_is_active AS STATE
FROM Table1 CA
JOIN Table2 CI ON CA.ID_CUSTOMER = CI.ID_CUSTOMER AND CI.ID_CUSTOMER = '11667312'
WHERE CA.STR_VALUE='Customer'
AND ci.bol_is_active ='N')
JOIN Table3 Cust ON TempID = cust.id_customer)
JOIN Table4 consumer ON TempID = consumer.id_customer;
I want to update the value of STATE , statuCust and stateConsumer.Please help.
You can do this as three separate UPDATE statements, since the values are in different tables. The three updates can be wrapped in a transaction so they are all done as a single operation.
The WHERE clause for each INSERT statement will look similar to the join and where clauses on the select, so the row to be updated matches the row shown by the select statement. I do not have time now to work out each INSERT statement, hopefully this points you in the right direction, and I will try to update this answer with more detail later.
BEGIN TRANSACTION ;
-- Update STATE
UPDATE Table2 SET bol_is_active WHERE ... ;
-- Update stateCust
UPDATE Table3 SET bol_is_active WHERE ... ;
-- Update stateConsumer
UPDATE Table4 SET bol_is_active WHERE ... ;
COMMIT;

Select Inside a select statement

I am trying to create a table in Database A from a table in database B. I have an idea with the query. In the database A, the table needs MerchantID and can get it from database B by using the query (Select MerchantID from Merchant_Location where LocationID= 'particular LocationID').
I need some help with the syntax for a query like this in SQL Server 2005. Thank you in advance!
INSERT INTO A.dbo.Merchant_Category (MerchantCategoryID, MerchantID)
SELECT MerchantLocationCategoryID, (MerchantID from Merchant_Location where LocationID = #Location) as MerchantID FROM B.dbo.Merchant_Location_Category
You want to use a SELECT INTO statement. What this does is execute a query and then inserts the results into your designated table.
SELECT field1, field2, field3 FROM db_b.TABLE_IN_DB_B
INTO db_a.TABLE_IN_DB_A;
Read more about the SELECT INTO statement Here
You can JOIN across databases in an INSERT, just like a SELECT. Most systems will allow it in an UPDATE as well.
INSERT INTO A.dbo.Merchant_Category (
MerchantCategoryID, MerchantID
)
SELECT LC.MerchantLocationCategoryID, L.MerchantId
FROM B.dbo.Merchant_Location_Category as LC
JOIN A.dbo.Merchant_Location as L ON
LC.LocationID = L.LocationID

Filter a SQL Server table dynamically using multiple joins

I am trying to filter a single table (master) by the values in multiple other tables (filter1, filter2, filter3 ... filterN) using only joins.
I want the following rules to apply:
(A) If one or more rows exist in a filter table, then include only those rows from the master that match the values in the filter table.
(B) If no rows exist in a filter table, then ignore it and return all the rows from the master table.
(C) This solution should work for N filter tables in combination.
(D) Static SQL using JOIN syntax only, no Dynamic SQL.
I'm really trying to get rid of dynamic SQL wherever possible, and this is one of those places I truly think it's possible, but just can't quite figure it out. Note: I have solved this using Dynamic SQL already, and it was fairly easy, but not particularly efficient or elegant.
What I have tried:
Various INNER JOINS between master and filter tables - works for (A) but fails on (B) because the join removes all records from the master (left) side when the filter (right) side has no rows.
LEFT JOINS - Always returns all records from the master (left) side. This fails (A) when some filter tables have records and some do not.
What I really need:
It seems like what I need is to be able to INNER JOIN on each filter table that has 1 or more rows and LEFT JOIN (or not JOIN at all) on each filter table that is empty.
My question: How would I accomplish this without resorting to Dynamic SQL?
In SQL Server 2005+ you could try this:
WITH
filter1 AS (
SELECT DISTINCT
m.ID,
HasMatched = CASE WHEN f.ID IS NULL THEN 0 ELSE 1 END,
AllHasMatched = MAX(CASE WHEN f.ID IS NULL THEN 0 ELSE 1 END) OVER ()
FROM masterdata m
LEFT JOIN filtertable1 f ON join_condition
),
filter2 AS (
SELECT DISTINCT
m.ID,
HasMatched = CASE WHEN f.ID IS NULL THEN 0 ELSE 1 END,
AllHasMatched = MAX(CASE WHEN f.ID IS NULL THEN 0 ELSE 1 END) OVER ()
FROM masterdata m
LEFT JOIN filtertable2 f ON join_condition
),
…
SELECT m.*
FROM masterdata m
INNER JOIN filter1 f1 ON m.ID = f1.ID AND f1.HasMatched = f1.AllHasMatched
INNER JOIN filter2 f2 ON m.ID = f2.ID AND f2.HasMatched = f2.AllHasMatched
…
My understanding is, filter tables without any matches simply must not affect the resulting set. The output should only consist of those masterdata rows that have matched all the filters where matches have taken place.
SELECT *
FROM master_table mt
WHERE (0 = (select count(*) from filter_table_1)
OR mt.id IN (select id from filter_table_1)
AND (0 = (select count(*) from filter_table_2)
OR mt.id IN (select id from filter_table_2)
AND (0 = (select count(*) from filter_table_3)
OR mt.id IN (select id from filter_table_3)
Be warned that this could be inefficient in practice. Unless you have a specific reason to kill your existing, working, solution, I would keep it.
Do inner join to get results for (A) only and do left join to get results for (B) only (you will have to put something like this in the where clause: filterN.column is null) combine results from inner join and left join with UNION.
Left Outer Join - gives you the MISSING entries in master table ....
SELECT * FROM MASTER M
INNER JOIN APPRENTICE A ON A.PK = M.PK
LEFT OUTER JOIN FOREIGN F ON F.FK = M.PK
If FOREIGN has keys that is not a part of MASTER you will have "null columns" where the slots are missing
I think that is what you looking for ...
Mike
First off, it is impossible to have "N number of Joins" or "N number of filters" without resorting to dynamic SQL. The SQL language was not designed for dynamic determination of the entities against which you are querying.
Second, one way to accomplish what you want (but would be built dynamically) would be something along the lines of:
Select ...
From master
Where Exists (
Select 1
From filter_1
Where filter_1 = master.col1
Union All
Select 1
From ( Select 1 )
Where Not Exists (
Select 1
From filter_1
)
Intersect
Select 1
From filter_2
Where filter_2 = master.col2
Union All
Select 1
From ( Select 1 )
Where Not Exists (
Select 1
From filter_2
)
...
Intersect
Select 1
From filter_N
Where filter_N = master.colN
Union All
Select 1
From ( Select 1 )
Where Not Exists (
Select 1
From filter_N
)
)
I have previously posted a - now deleted - answer based on wrong assumptions on you problems.
But I think you could go for a solution where you split your initial search problem into a matter of constructing the set of ids from the master table, and then select the data joining on that set of ids. Here I naturally assume you have a kind of ID on your master table. The filter tables contains the filter values only. This could then be combined into the statement below, where each SELECT in the eligble subset provides a set of master ids, these are unioned to avoid duplicates and that set of ids are joined to the table with data.
SELECT * FROM tblData INNER JOIN
(
SELECT id FROM tblData td
INNER JOIN fa on fa.a = td.a
UNION
SELECT id FROM tblData td
INNER JOIN fb on fb.b = td.b
UNION
SELECT id FROM tblData td
INNER JOIN fc on fc.c = td.c
) eligible ON eligible.id = tblData.id
The test has been made against the tables and values shown below. These are just an appendix.
CREATE TABLE tblData (id int not null primary key identity(1,1), a varchar(40), b datetime, c int)
CREATE TABLE fa (a varchar(40) not null primary key)
CREATE TABLE fb (b datetime not null primary key)
CREATE TABLE fc (c int not null primary key)
Since you have filter tables, I am assuming that these tables are probably dynamically populated from a front-end. This would mean that you have these tables as #temp_table (or even a materialized table, doesn't matter really) in your script before filtering on the master data table.
Personally, I use the below code bit for filtering dynamically without using dynamic SQL.
SELECT *
FROM [masterdata] [m]
INNER JOIN
[filter_table_1] [f1]
ON
[m].[filter_column_1] = ISNULL(NULLIF([f1].[filter_column_1], ''), [m].[filter_column_1])
As you can see, the code NULLs the JOIN condition if the column value is a blank record in the filter table. However, the gist in this is that you will have to actively populate the column value to blank in case you do not have any filter records on which you want to curtail the total set of the master data. Once you have populated the filter table with a blank, the JOIN condition NULLs in those cases and instead joins on itself with the same column from the master data table. This should work for all the cases you mentioned in your question.
I have found this bit of code to be faster in terms of performance.
Hope this helps. Please let me know in the comments.

SQL Server Update with Inner Join

I have 3 tables (simplified):
tblOrder(OrderId INT)
tblVariety(VarietyId INT,Stock INT)
tblOrderItem(OrderId,VarietyId,Quantity INT)
If I place an order, I drop the stock level using this:
UPDATE tblVariety
SET tblVariety.Stock = tblVariety.Stock - tblOrderItem.Quantity
FROM tblVariety
INNER JOIN tblOrderItem ON tblVariety.VarietyId = tblOrderItem.VarietyId
INNER JOIN tblOrder ON tblOrderItem.OrderId = tblOrder.OrderId
WHERE tblOrder.OrderId = 1
All fine, until there are two rows in tblOrderItem with the same VarietyId for the same OrderId. In this case, only one of the rows is used for the stock update. It seems to be doing a GROUP BY VarietyId in there somehow.
Can anyone shed some light? Many thanks.
My guess is that because you have shown us simplified schema, some info is missing that would determine why have the repeated VarietyID values for a given OrderID.
When you have multiple rows, SQL Server will arbritrarily pick one of them for the update.
If this is the case, you need to group first
UPDATE V
SET
Stock = Stock - foo.SumQuantity
FROM
tblVariety V
JOIN
(SELECT SUM(Quantity) AS SumQuantity, VarietyID
FROM tblOrderItem
JOIN tblOrder ON tblOrderItem.OrderId = tblOrder.OrderId
WHERE tblOrder.OrderId = 1
GROUP BY VarietyID
) foo ON V.VarietyId = foo.VarietyId
If not, then the OrderItems table PK is wrong because if allows duplicate OrderID/VarietyID combinations (The PK should be OrderID/VarietyID, or these should be constrained unique)
From the documentation UPDATE
The results of an UPDATE statement are
undefined if the statement includes a
FROM clause that is not specified in
such a way that only one value is
available for each column occurrence
that is updated (in other words, if
the UPDATE statement is not
deterministic). For example, given the
UPDATE statement in the following
script, both rows in table s meet the
qualifications of the FROM clause in
the UPDATE statement, but it is
undefined which row from s is used to
update the row in table t.
CREATE TABLE s (ColA INT, ColB DECIMAL(10,3))
GO
CREATE TABLE t (ColA INT PRIMARY KEY, ColB DECIMAL(10,3))
GO
INSERT INTO s VALUES(1, 10.0)
INSERT INTO s VALUES(1, 20.0)
INSERT INTO t VALUES(1, 0.0)
GO
UPDATE t
SET t.ColB = t.ColB + s.ColB
FROM t INNER JOIN s ON (t.ColA = s.ColA)
GO
You are doing an update. It will update once.
Edit: to solve, you can add in a subquery that will group your orderitems by orderid and varietyid, with a sum on the amount.

ANSI SQL question

I have a table which has fields (id, parent_id, name, created_at). I want to write a query to select id, name, created_at, parent_created_at. The 'parent_created_at' is the 'created_at' field for the records matching parent (if it has one - i.e. the records parent_id >0), otherwise the 'parent_created_at' field should be null. Any suggestions?
Self Join + ANSI SQL CASE Expression
SELECT t.id
, t.name
, t.created_at
, CASE WHEN t.parent_id > 0 THEN p.created_at ELSE NULL END AS parent_created_at
FROM Table t
JOIN Table p
ON t.id = p.parent_id
Morpheous,
You only have two rows in your table, so please take the trouble to give all the details! All you tell us is what their parent_ids are, and your query's join condition depends on more than that.
Can you fill in the ... below so we know the full details?
CREATE TABLE t(...
INSERT INTO t VALUES (...
INSERT INTO t VALUES (...