Sql Server Ignore update errors - sql

I have inherited a very old database that needs some data to be updated. Each row ha a column with a UniqueID that looks like C0042-45-39612. The last 3 numbers of the code are the category Id (in this case 612).
I need to do an update that targets only certain categories and I'm using this SQL statement
UPDATE WebbikesProducts SET Price = Price * 1.05 WHERE Convert( Integer, SubString( UniqueID, 3, 3 )) = 125
The obvious problem here is what if the unique code doesn't have 3 numbers at the end? Well that's exactly the problem I have as not all the items are categorized or have unique numbers like C0049-307-1CHROME.
I don't have access to the DB (I'm calling this from an asp page) so I'd prefer not to have to create a stored procedure. The DB is SQL 2000.
Is there any way to ignore the rows with errors and carry on updating the other rows?

Try this:
UPDATE WebbikesProducts
SET Price = Price * 1.05
WHERE ISNUMERIC(SubString( UniqueID, 3, 3 )) = 1
AND Convert( Integer, SubString( UniqueID, 3, 3 )) = 125
or even more simple:
UPDATE WebbikesProducts
SET Price = Price * 1.05
WHERE SubString( UniqueID, 3, 3 ) = '125'
-Edo

I'm not sure why you are bothering converting to an int. Why not just do a string compare for the last three digits. Also, you are doing - substring(id, 3, 3).
I assume you have simplified the above snippet to make it easier to read and that you are already extracting the 39612 first?
I would suggest the following:
where UniqueID like '%612'

Related

Given a table of numbers, can I get all the rows which add up to less than or equal to a number?

Say I have a table with an incrementing id column and a random positive non zero number.
id
rand
1
12
2
5
3
99
4
87
Write a query to return the rows which add up to a given number.
A couple rules:
Rows must be "consumed" in order, even if a later row makes it a a perfect match. For example, querying for 104 would be a perfect match for rows 1, 2, and 4 but rows 1-3 would still be returned.
You can use a row partially if there is more available than is necessary to add up to whatever is leftover on the number E.g. rows 1, 2, and 3 would be returned if your max number is 50 because 12 + 5 + 33 equals 50 and 90 is a partial result.
If there are not enough rows to satisfy the amount, then return ALL the rows. E.g. in the above example a query for 1,000 would return rows 1-4. In other words, the sum of the rows should be less than or equal to the queried number.
It's possible for the answer to be "no this is not possible with SQL alone" and that's fine but I was just curious. This would be a trivial problem with a programming language but I was wondering what SQL provides out of the box to do something as a thought experiment and learning exercise.
You didn't mention which RDBMS, but assuming SQL Server:
DROP TABLE #t;
CREATE TABLE #t (id int, rand int);
INSERT INTO #t (id,rand)
VALUES (1,12),(2,5),(3,99),(4,87);
DECLARE #target int = 104;
WITH dat
AS
(
SELECT id, rand, SUM(rand) OVER (ORDER BY id) as runsum
FROM #t
),
dat2
as
(
SELECT id, rand
, runsum
, COALESCE(LAG(runsum,1) OVER (ORDER BY id),0) as prev_runsum
from dat
)
SELECT id, rand
FROM dat2
WHERE #target >= runsum
OR #target BETWEEN prev_runsum AND runsum;

How can I select new created rows without old, unupdated row?

I have a database that I'm searching through that is sometimes updated by another person. The way it is updated is terrible, but I can't change it. What happens is the updated numbers contain a "-1" or "-2". For example,
ID
1
2
3
4
Whenever one ID is updated, a new row is created like so:
ID
1
1-1
2
3
4
In this case, 1 was updated. Both 1 and 1-1 show up in the table. If it's updated again, it looks like this:
ID
1
1-1
1-2
2
3
4
It makes me furious but I can't do anything about it. I would like to select the rows in a query such that I get
ID
1-2
2
3
4
Does anybody have any suggestions?
I am assuming your IDs are strings since you can use - in them. You can create a saved query with your entire table and two additional columns:
OriginalID: IIf(InStr([ID],'-')=0,[ID],CInt(Left([ID],InStr([ID],'-')-1)))
and
Version: IIf(InStr([ID],'-')=0,0,CInt(Right([ID],Len([ID])-InStr([ID],'-'))))
This converts the number after the dash to an actual number (and zero for the original version).
Then use
SELECT [OriginalID] & IIF(Max([Version])=0,'','-' & Max([Version])) AS MaxID
FROM [MySavedQuery]
GROUP BY [OriginalID]
I have not had a chance to test this so there may be a parenthesis missing here or there or you may have to add a +1 or -1 to some lengths, but it should get you most of the way there.
First, split off the part of the ID without the dash, and set it to 0 if there is no dash:
SELECT ID,
CLng(IIF(ID Like "*-*", Right(ID, Len(ID) - InStr(1, ID, "-")), 0)) As LastPartID,
CLng(IIF(ID LIKE "*-*", Left(ID, InStr(1, ID, "-") - 1), ID)) As FirstPartID
From MyTable
If you save this as a separate query, the next query is simple:
SELECT FirstPartID & IIF(Max(LastPartID) = 0, "", "-" & Max(LastPartID))
FROM MyQuery
GROUP By FirstPartID

SQL Query - Limited by another SQL query of a different data type

I need some help on this one. I have a query that I need to make work but I need to limit it by the results of another query.
SELECT ItemID, ItemNums
FROM dbo.Tables
ItemNums is a varchar field that is used to store the strings of the various item numbers.
This produces the following.
ItemID ItemNums
1 1, 4, 5
2 1, 3, 4, 5
3 2
4 4
5 1
I have another table that has each item number as an INT that I need to use to pull all ItemIDs that have the associated ItemNums
Something like this.
SELECT *
FROM dbo.Tables
WHERE ItemNums IN (4,5)
Any help would be appreciated.
If possible, you should change your database schema. In general, it's not good to store comma delimited lists in a relational database.
However, if that's not an option, here's one way using a join with like:
select *
from dbo.Tables t
join dbo.SecondTable st on ', '+t.ItemNums+',' like '%, '+st.ItemNumId+',%'
This concatenates commas to the beginning and end of the itemnums to ensure you only match on the specific ids.
I personally would recommend normalizing your dbo.tables.
It would be better as:
ItemID ItemNums
1 1
1 4
1 5
2 1
etc.
Then you can use a join or a sub query to pull out the rows with ItemNums in some list.
Otherwise, it's going to be a mess and not very fast.

SQL - How to update a field in a record to summed value from two tables

I'm having a problem getting a table to update and am hoping that maybe someone here can help me out. I'm just learning SQL, so I'm not sure of the best way to do certain processes. I have a value in one of my tables that somehow got out of whack. Now, I need to update it using the original value minus the sum of values in a different table.
Table 1 is ORDER_LINES.
ORDER_NO QTY_ON_ORD ORIG_ORD_QTY
0900476 10 100
Table 2 is INVOICED_LINES.
INV_NO SHIP_QTY ORIG_ORD_NO
000441 20 0900476
000441 25 0900476
000441 15 0900476
000441 10 0900476
Value of ORDER_LINES.QTY_ON_ORD should be:
ORDER_LINES.QTY_ON_ORD =
ORDER_LINES.ORIG_ORD_QTY - SUM(INVOICED_LINES.SHIP_QTY)
WHERE INVOICED_LINES.ORIG_ORD_NO = ORDER_LINES.ORDER_NO
So, the value of ORDER_LINES.QTY_ON_ORD is not correct. The values in these are constantly changing, so I'd like to have a SQL command that I can run to update these on the fly. I've tried many things such as:
UPDATE "ORDER_LINES"
SET QTY_ON_ORD = SELECT (
(SELECT SUM(ORIG_ORD_QTY) FROM "ORDER_LINES" WHERE ORDER_NO = '0900476') -
(SELECT SUM(SHIP_QTY) FROM "INVOICED_LINES" WHERE ORIG_ORD_NO = '0900476')
)
WHERE ORDER_NO = '0900476';
But that doesn't work. The Selects by themselves print out the correct qty in my query, but I can't seem to use that qty in my update.
We're running Pervasive SQL if that makes any difference.

SQL Select using distinct and Cast [duplicate]

This question already exists:
Closed 10 years ago.
Possible Duplicate:
SQL Select DISTINCT using CAST
Let me try this one more time... I'm not a sql guy so please bear with me as I try to explain this... I have a table called t_recordkeepingleg with three columns of data. Column1 is named LEGTRIPNUMBER that happens to be a string that starts with the letter Q followed by 4 numbers. I need to strip off the Q and convert the remaining 4 characters (numbers) to an integer. Everyone with me so far? Column2 of this table is named LEGDATE. Column3 is named LEGGROUP.
Here's the input scenario
LEGTRIPNUMBER LEGDATE LEGGROUP
Q1001 08/12/12 0001
Q1001 09/15/12 0002
Q1002 09/01/12 0001
Q1002 09/08/12 0003
Q1002 09/09/12 0002
As you can see the input table has rows where LEGTRIPNUMBER occurs more than once. I only want the first occurrence.
This is my current select statement - it works but returns all rows.
SELECT *,
CAST(
substring("t_RecordkeepingLeg"."LEGTRIPNUMBER",2,4) as INT
) as Num_Trip_Num
FROM "1669"."dbo"."t_RecordkeepingLeg" "t_RecordkeepingLeg"
Where left "t_RecordkeepingLeg"."LEGTRIPNUMBER",1) = 'Q'
I want to modify this so that it only selects ONE occurance of the Qnnnn. When the row gets selected I want to have LEGDATE and LEGGROUP available to me. How do I do this?
Thank you,
Can it be as simple as below? I've just added condiotion on leggroup being 0001
SELECT *,
CAST(substring("t_RecordkeepingLeg"."LEGTRIPNUMBER",2,4) as INT) as Num_Trip_Num
FROM "1669"."dbo"."t_RecordkeepingLeg" "t_RecordkeepingLeg"
Where left ("t_RecordkeepingLeg"."LEGTRIPNUMBER",1) = 'Q'
and "t_RecordkeepingLeg"."LEGGROUP"='0001'
If you have a unique primay key in your table you can do something like the below;
SELECT CAST(
substring("t_RecordkeepingLeg"."LEGTRIPNUMBER",2,4) as INT
) as Num_Trip_Num
FROM "1669"."dbo"."t_RecordkeepingLeg" "t_RecordkeepingLeg"
Where "t_RecordkeepingLeg"."ID" In(
Select Min("t_RecordkeepingLeg"."ID")
From "1669"."dbo"."t_RecordkeepingLeg" "t_RecordkeepingLeg"
Where left ("t_RecordkeepingLeg"."LEGTRIPNUMBER",1) = 'Q'
Group By "t_RecordkeepingLeg"."LEGTRIPNUMBER"
)
Which values of LEGDATE & LEGGROUP do you want for the distinct LEGTRIPNUMBER? there are multiple non-distinct possibilities and the concept of "first occurrence" is only valid with an explicit order.
To get the values where LEGDATE is the earliest for example;
select Num_Trip_Num, LEGDATE, LEGGROUP from (
select
cast(substring(t_RecordkeepingLeg.LEGTRIPNUMBER, 2, 4) as INT) as Num_Trip_Num,
row_number() over (partition by substring(t_RecordkeepingLeg.LEGTRIPNUMBER, 2, 4) order by t_RecordkeepingLeg.LEGDATE asc) as row,
t_RecordkeepingLeg.LEGDATE,
t_RecordkeepingLeg.LEGGROUP
from t_RecordkeepingLeg
where left (t_RecordkeepingLeg.LEGTRIPNUMBER, 1) = 'Q'
) T
where row = 1