Curious to know one simple SQL concept in SQL Server.
I have two tables, based on certain IF condition , I would like to update and insert data from different tables.I'm using below query for this in side a stored procedure.
IF( SELECT COUNT(colname) FROM [dbo].[Table_BKP] WHERE colname LIKE ('%Dear(DEC''D)444-0292/555-4528C%'))> 0
BEGIN
;WITH Dear AS
(
SELECT ID,colname,SUBSTRING(colname,PATINDEX('%(DEC''D)%',colname),LEN(colname)-1) AS colname_4SUPPL,LEFT(colname,PATINDEX('%(DEC''D)%',colname)-1) AS colname_4MAIN
FROM [dbo].[Table_BKP] WHERE RTRIM(LTRIM(colname)) LIKE ('Dear(DEC''D)444-0292/555-4528C')
) SELECT * INTO Dear_ FROM Dear
UPDATE A SET A.colname = B.colname_4MAIN FROM Table AS A INNER JOIN
Dear_ AS B ON A.ID = B.ID
INSERT INTO Table_SUPPL(ID,colnameMSC,[SOURCE],[TARGET])
SELECT ID,replace(colname_4SUPPL,'(DEC''D)',''),'colname','colnameMSC'
FROM Dear_
END
update statement is working fine and data is getting updated into the required table.However, the data is not getting inserted into the required table.
But, when I changed the sequence as below, it worked perfectly.
IF( SELECT COUNT(colname) FROM [dbo].[Table_BKP] WHERE colname LIKE ('%Dear(DEC''D)444-0292/555-4528C%'))> 0
BEGIN
;WITH Dear AS
(
SELECT ID,colname,SUBSTRING(colname,PATINDEX('%(DEC''D)%',colname),LEN(colname)-1) AS colname_4SUPPL,LEFT(colname,PATINDEX('%(DEC''D)%',colname)-1) AS colname_4MAIN
FROM [dbo].[Table_BKP] WHERE RTRIM(LTRIM(colname)) LIKE ('Dear(DEC''D)444-0292/555-4528C')
) SELECT * INTO Dear_ FROM Dear
INSERT INTO Table_SUPPL(ID,colnameMSC,[SOURCE],[TARGET]) SELECT
ID,replace(colname_4SUPPL,'(DEC''D)',''),'colname','colnameMSC' FROM
Dear_
UPDATE A SET A.colname = B.colname_4MAIN FROM Table AS A INNER JOIN
Dear_ AS B ON A.ID = B.ID
END
Why, the formar quesry is not working as expected? And, the later one [just after changing sequesnce (1st INSERT then Update)]; Its working perfectly...How SQL Server manages these sequence? Could anyone please clarify this simple doubt? Thanks.
Related
I am writing a query which gives me strange result or i am doing something wrong. I am using IN operator in where clause. I revive country_id(nullable),province_id (nullable) and city_id(nullable) from application. If city_id is not null then i extract all centre_id that exist in that city_id and stored in temp table. If city_id is null and province_id is not null then i extract all centre_id that exist in that province_id and in the same way if city_id and province_id both are null then i extract centre_id that exist in country_id and if all 3 are null then i extract all centre_id and stored in temp table like below:
DECLARE #serviceCenter TABLE (service_center_id INT)
IF (#city_id IS NOT NULL)
BEGIN
INSERT INTO #serviceCenter
SELECT service_centre_id
FROM ServiceCentre
WHERE city_id= #city_id
END
ELSE IF (#province_id IS NOT NULL)
BEGIN
INSERT INTO #serviceCenter
SELECT service_centre_id
FROM ServiceCentre
INNER JOIN City ON City .city_id= ServiceCentre.city_id
INNER JOIN Province ON Province.province_id= City.province_id
WHERE Province.province_id= #province_id
END
ELSE IF (#country_id IS NOT NULL)
BEGIN
INSERT INTO #serviceCenter
SELECT service_centre_id
FROM ServiceCentre
INNER JOIN City ON City .city_id= ServiceCentre.city_id
INNER JOIN Province ON Province.province_id= City.province_id
INNER JOIN Country ON Country.country_id= City.country_id
WHERE Country.country_id = #country_id
END
ELSE
BEGIN
INSERT INTO #serviceCenter
SELECT service_centre_id
FROM ServiceCentre
END
Now on the basis of service centers i need to get transaction count like below.
**Select Count(1)
From Tranactions
where service_centre_id IN (Select service_centre_id From #serviceCenter)**
Now the problem is this query gives the all transactions from all center_id. I checked it. If there is only one id in temp table and value is 1 it gives me all transactions. And when i run below query with hard code value, it gives the correct result
**Select Count(1)
From Tranactions
where service_centre_id IN (1)**
What's the different between where service_centre_id IN (Select service_centre_id From #serviceCenter) and where service_centre_id IN (1).
What's the problem?
The problem is this query fetch all service_center_id:
#serviceCenter must be a table name.
where center_id IN (Select service_centre_id From #serviceCenter)
and the another one is just select only contains 1 service_center_id
where center_id IN (1)
First of all, you can severely simplify this query by using COALESCE(), as such:
INSERT INTO #serviceCenter
SELECT COALESCE(City.service_centre_id,Provice.service_centre_id,Country.service_centre_id,ServiceCentre.service_centre_id)
FROM ServiceCentre
LEFT JOIN City
ON City.city_id = ServiceCentre.city_id
AND City.City_ID = #city_id
LEFT JOIN Province
ON Province.province_id = City.province_id
AND Province.province_id = #province_id
LEFT JOIN Country
ON Country.country_id = City.country_id
AND Country.country_id = #country_id
;
Each JOIN here uses the proper table joins, together with the parameter condition you want matched. Because we're using LEFT JOIN, any condition that isn't matched will return a NULL value from that table.
The COALESCE() function takes a list of expressions and returns the first one that isn't NULL, so by ordering the expressions within the COALESCE() function to you're liking, you can tell it, "Try to bring me the City.service_centre_id first, then the Province.service_centre_id, then the Country.service_centre_id..." and so on.
Judging from what you're describing, I'm wondering if the problem isn't in the values being passed into the query in the parameters. If you can write it out manually:
SELECT COUNT(1)
FROM Tranactions
WHERE center_id IN (1)
;
and this gives you the right result, then the problem is probably in the value being passed.
The end of your original query:
INSERT INTO #serviceCenter
SELECT service_centre_id
FROM ServiceCentre
;
seems to pass all service_centre_id values into the #serviceCenter variable.
Is it possible that the parameters aren't being passed properly, and thus all service_center_ids are being selected into the table variable, which would then cause you to receive a count of all transactions for all servicecenters?
Note: To check this, you can run a simple SELECT * FROM #serviceCenter at the end of your IF...ELSE series to see what values are returned. My suspicion is that you'll get a few more than what you wanted.
Finally after 2 hours i found the mistake and mistake was nothing except the spell mistake. First of all i apologize because in question i used center_id but it was actually service_centre_id. However i updated the question. Now come to the problem. The declaration of the table was below:
**DECLARE #serviceCenter TABLE (service_center_id INT)
and the where clause was below:
Select Count(1)
From Tranactions
where service_centre_id IN (Select service_centre_id From #serviceCenter)
The problem was in service_centre_id .
The transactions table contains the column service_centre_id and in IN operator query i was using service_centre_id instead of service_center_id . Because while declaring table i set the column name as service_center_id. So the actual mistake was i was using service_centre_id instead of service_center_id and there was spell mistake.
I have a WITH statement that collects the data I want. What I want to do is to be able to do a SELECT from different parts of my WITH and INSERT that result into a destination table.
Here is a simplified version of my long query:
WITH Active AS (
--SELECT 1
),
Inactive AS (
--SELECT 2
),
Churn AS (
--SELECT 3
)
--Drop destination table if exists
IF OBJECT_ID('DestinationTable', 'u') IS NOT NULL DROP TABLE DestinationTable;
SELECT Active.Name, Inactive.Name,Churn.Id
INTO DestinationTable
FROM Active a
JOIN Inactive i ON a.Id = i.Id
JOIN Churn c ON a.Id = c.Id;
But Sql Server does not allow an IF statement directly after a WITH. I do not want to move the IF before my WITH because then it will be likely that my destination table be empty for a long time.
Simple version of my question:
How can I write a SELECT from a WITH statement into another table?
Because it is compulsory to use with statement result follow by with statement.
Any other statement except with result not allowed.
You can write your drop statement above the with statement
Just restructure it like this:
--Drop destination table if exists
IF OBJECT_ID('DestinationTable', 'u') IS NOT NULL DROP TABLE DestinationTable
;WITH Active AS (
--SELECT 1
),
Inactive AS (
--SELECT 2
),
Churn AS (
--SELECT 3
)
SELECT Active.Name, Inactive.Name,Churn.Id
INTO DestinationTable
FROM Active a
JOIN Inactive i ON a.Id = i.Id
JOIN Churn c ON a.Id = c.Id;
The scope of the CTE means it needs to be used in the statement immediately after it's declaration.
Otherwise you need some other staging area to handle the load before you replace the destination table.
In SSMS 2014 I have a working SELECT query and want to convert it to and UPDATE statement to update a field in the main table. I have tried and tried many solutions, each results in a different error.
I've managed to do simple UPDATE SET WHERE queries before, but this is a little more complex using derived tables in the WHERE clause. On Searching I found a JOIN solution but for me it does not like the RIGHT or JOIN and in that solution the SET was the last line and SSMS does not like that either so I getting a little confused now.
This is my working SELECT Statement that selects the correct SKU's:
SELECT
dbo.tblHKProducts.SKU_ID, dbo.tblHKProducts.SKU_Description,
dbo.tblHKProducts.SKU_Scan_Group
FROM
dbo.tblHKProducts
RIGHT OUTER JOIN
(SELECT
tblHKProducts_1.SKU_ID, tblHKProducts_1.SKU_Description,
dbo.ForceScanByDescriptions.FindDescription
FROM
dbo.tblHKProducts AS tblHKProducts_1
RIGHT OUTER JOIN
dbo.ForceScanByDescriptions ON tblHKProducts_1.SKU_Description = dbo.ForceScanByDescriptions.FindDescription
WHERE
(tblHKProducts_1.SKU_Description IS NOT NULL)
) AS derivedtbl_1 ON dbo.tblHKProducts.SKU_ID = derivedtbl_1.SKU_ID
I'm trying to do something like this, SKU_Scan_Group is a field in tblHKProducts:
UPDATE dbo.tblHKProducts
SET SKU_Scan_Group = N'Yes'
RIGHT OUTER JOIN
(SELECT
tblHKProducts_1.SKU_ID, tblHKProducts_1.SKU_Description,
dbo.ForceScanByDescriptions.FindDescription
FROM
dbo.tblHKProducts AS tblHKProducts_1
RIGHT OUTER JOIN
dbo.ForceScanByDescriptions ON tblHKProducts_1.SKU_Description = dbo.ForceScanByDescriptions.FindDescription
WHERE
(tblHKProducts_1.SKU_Description IS NOT NULL)
) AS derivedtbl_1 ON dbo.tblHKProducts.SKU_ID = derivedtbl_1.SKU_ID
Any help would be appreciated!
Thanks
Kev
This is quite simple, actually. This should work:
UPDATE P
SET P.SKU_Scan_Group = N'Yes'
-- SELECT P.SKU_ID, P.SKU_Description, P.SKU_Scan_Group
FROM dbo.tblHKProducts AS P
RIGHT JOIN (
SELECT P1.SKU_ID
, P1.SKU_Description
, FSBD.FindDescription
FROM dbo.tblHKProducts AS P1
RIGHT JOIN dbo.ForceScanByDescriptions AS FSBD
ON P1.SKU_Description = FSBD.FindDescription
WHERE P1.SKU_Description IS NOT NULL
) AS derivedtbl_1
ON P.SKU_ID = derivedtbl_1.SKU_ID;
P.S.
Start using aliases to reference tables your code might become quite hard to maintain later.
I can easily create a stored procedure in SQL Server with parameters that I use with =, LIKE and most operators. But when it comes to using IN, I don't really understand what to do, and I can't find a good site to teach me.
Example
CREATE PROCEDURE TEST
#Ids --- What type should go here?
AS BEGIN
SELECT * FROM TableA WHERE ID IN ( #Ids )
END
Is this possible and if so how ?
With SQL Server 2008 and above, you can use Table Valued Parameters.
You declare a table type and can use that as a parameter (read only) for stored procedures that can be used in IN clauses.
For the different options, I suggest reading the relevant article for your version of the excellent Arrays and Lists in SQL Server, by Erland Sommarskog.
I've done this in the past using a Split function that I add to my schema functions as described here
Then you can do the following:
CREATE PROCEDURE TEST
#Ids --- What type should go here?
AS BEGIN
SELECT * FROM TableA WHERE ID IN ( dbo.Split(#Ids, ',') )
END
Just remember that the IN function always expects a table of values as a result. SQL Server is smart enough to convert strings to this table format, so long as they are specifically written in the procedure.
Another option in your specific example though, could be to use a join. This will have a performance improvement, but often does not really meet a real-world example you need. The join version would be:
SELECT *
FROM TableA AS ta
INNER JOIN dbo.Split(#Ids, ',') AS ids
ON ta.Id = ids.items
If your asking what I think your asking, I do this every day..
WITH myData(FileNames)
AS
(
SELECT '0608751970%'
UNION ALL SELECT '1000098846%'
UNION ALL SELECT '1000101277%'
UNION ALL SELECT '1000108488%'
)
SELECT DISTINCT f.*
FROM tblFiles (nolock) f
INNER JOIN myData md
ON b.FileNames LIKE md.FileNames
Or if your doing this based on another table:
WITH myData(FileNames)
AS
(
SELECT RTRIM(FileNames) + '%'
FROM tblOldFiles
WHERE Active=1
)
SELECT DISTINCT f.*
FROM tblFiles (nolock) f
INNER JOIN myData md
ON b.FileNames LIKE md.FileNames
I got a nested query which I'm trying to run; however I have to screen for numbers with a -1 I have the following:
update invoices set type = 5 where tranno like dbo._fnStripLeadZeroes((
select invoice_number from [bob.jupiter.com].webap.dbo.billinglog)) + '-1'
with invoice_number(varchar15) and tranno(varchar10)
am i approaching this correctly?
This shouldn't be a nested query. What you want is to join the invoices table to the billingLog table to determine which rows to join.
Using the 'update/set/from/where' syntax lets you use a join in your update and it reads nicely.
I used a common table expression [the ;with billing as (..)] part to help simplifiy your query.
Finally, I changed the LIKE to an '=' because you weren't using wildcards, so the like was functioning as an equals anyways.
;with billing as
(
select dbo._fnStripLeadZeros(invoice_number) + '-1' as invoice_number
from [bob.jupiter.com].webapp.dbo.billinglog
)
update inv
set inv.type = 5
from invoices inv
inner join billing b
on (inv.tranno = b.invoice_number )