SQL delete objects having and id range - sql

I want to create a function in sql server that take as input an id range and delete all the object in that range (included the start and the end).
Let's have for example:
delete_objects_with_id(id_start,id_end)
It will delete all the objects with the id in the range id_start and id_end.
The problem is that the id are of this form: id_start=2017-0001 id_end=2017-0050 is there a sql server function that iterate on a list given a range?
first_issue content id
2011-01-01 test 2011-0001
2012-10-01 test 2012-0001
2012-11-01 test 2012-0002
2012-11-01 test 2012-0003

No, there's no builtin SQL Server function that will iterate on a list given a range.
If the id values are always nine characters, in the format four numeric digits, a dash and four more digits, then a comparison to character strings would get you the id values.
That is, you could write a query (SQL SELECT statement) to return the id values in that range,
SELECT t.id
FROM myobjects t
WHERE t.id >= '2017-0001'
AND t.id <= '2017-0050'
ORDER BY t.id
and with that query, you could define a cursor loop, and loop through (iterate) through those id values returned.
If the id values aren't in a canonical format, then the range operation isn't necessarily going to work. You'd need a mechanism to convert the id values into values that are canonical, so you can do a range.
But I'm not getting why you would need (or want) to iterate, if by "objects" you are referring to "rows" in a table. If you can write a SELECT statement that returns those rows, you could write a DELETE statement using the same predicates, and delete the rows in one fell swoop.
DELETE
FROM myobjects
WHERE id >= '2017-0001'
AND id <= '2017-0050'
It's not at all clear what you are attempting to achieve, why you would need to "iterate". But a cursor loop is one way to do that.
Again, to answer the question you asked: No. There is no "sql server function that iterate on a list given a range"

There is a simple workaround, Just remove - character and cast id as BIGINT
(This will work assuming that the first part of the id is year value and the second part is an id for each year)
DELETE FROM TABLE_1
WHERE CAST(REPLACE(id,'-','') as BIGINT) >= CAST(REPLACE(id_start,'-','') as BIGINT)
AND CAST(REPLACE(id,'-','') as BIGINT) <= CAST(REPLACE(id_end,'-','') as BIGINT)
Or use BETWEEN
DELETE FROM TABLE_1
WHERE CAST(REPLACE(id,'-','') as BIGINT) BETWEEN CAST(REPLACE(id_start,'-','') as BIGINT)
AND CAST(REPLACE(id_end,'-','') as BIGINT)

Related

How to Extract only numbers from the String without using function in SQL

Table contains data as below
Table Name is REGISTER
Column Name is EXAM_CODE
Values like ('S6TJ','S7','S26','S24')
I want answer like below
Result set - > (6,7,26,24)
Please suggest solution - since regexp_replace is not recognized built in function name in SQL.
The complexity of the answer depends on two things: the RDBMS used and whether the numbers in the EXAM_CODE are contiguous.
I have assumed that the RDBMS is SQL Server and the numbers in EXAM_CODE are always contiguous. If not, please advise and I can revise the answer.
The following SQL shows a way of accomplishing the above using PATINDEX.:
CREATE TABLE #REGISTER (EXAM_CODE VARCHAR(10));
INSERT INTO #REGISTER VALUES ('S6TJ'),('S7'),('S26'),('S24');
SELECT LEFT(EXAM_CODE, PATINDEX('%[^0-9]%', EXAM_CODE) - 1)
FROM (
SELECT RIGHT(EXAM_CODE, LEN(EXAM_CODE) - PATINDEX('%[0-9]%', EXAM_CODE) + 1) + 'A' AS EXAM_CODE
FROM #REGISTER
) a
DROP TABLE #REGISTER
This outputs:
6
7
26
24
PATINDEX matches a specified pattern against a string (or returns 0 if there is no match).
Using this, the inner query fetches all of the string AFTER the first occurence of a number. The outer query then strips any text that may appear on the end of the string.
Note: The character A is appended to the result of the inner query in order to ensure that the PATINDEX check in the outer query will make a match. Otherwise, PATINDEX would return 0 and an error would occur.

Strange behaviour of SQL Server query

I have a query in a validation stored procedure. It goes something like this:
SELECT *
FROM Table1
WHERE batchID IN (SELECT id FROM #tempIds)
AND CAST(field1 AS DATE) > CAST(field2 AS DATE)
Both field1 and field2 have valid dates, i.e. doing IdDate on field1/2 returns 1.
The #tempIds table only has one column ID and contains only one row.
When I run the above query, I get this error:
Unable to convert varchar to date
But instead of selecting batch ids from temp table if I put hard-coded ID from the same temp table it works.
Any ideas what could be the issue?
The problem is that you are using varchar to store date (or datetime) values.
Choosing the correct data type for your columns would save you from a lot of problems, this one included. For detailed information, read Aaron Bertrand's Bad habits to kick : choosing the wrong data type.
Now, to address our conversation in the comments - SQL Server does not guarantee the order on which the conditions in the where clause are evaluated. This means that even if all the "date" strings in both your columns are convertible to date values for the specific batchID, you only need one wrong value in one of the columns to raise the "Unable to convert varchar to date" error.
This also means that even if you where to write your query the way Larry B suggested in his answer (now deleted - so for the sake of future readers - this was his suggestion:)
SELECT *
FROM Table1
WHERE batchID IN (SELECT id FROM #tempIds)
AND ISDATE(field1) = 1
AND ISDATE(field2) = 1
AND CAST(field1 AS DATE) > CAST(field2 AS DATE)
There is no guarantee that the last condition (cast(field1 as date) > cast(field2 as date)) will be evaluated after the isdate(field1)=1 condition.
The correct thing to do is to fix the problem - change the data types of the columns to the correct data type.
Assuming that can't be done (if you have no control over the structure of the database, for instance) - you can do a couple of things:
Find all the places where the values in field1 and in field2 can't be converted to dates and fix them. Consider adding a check constraint to validate that the values of these columns can be converted to date (assuming you can).
Separate your query into 2 parts:
;With cte as
(
SELECT *
FROM Table1
WHERE batchID IN (SELECT id FROM #tempIds)
AND ISDATE(field1) = 1
AND ISDATE(field2) = 1
)
SELECT *
FROM cte
WHERE CAST(field1 AS DATE) > CAST(field2 AS DATE)
This will eliminate the error, since you are only casting values where the ISDATE function already returned 1, but might not return some rows you want back, if the value if either field1 or field2 is wrong in these rows.

Convert select into stored procedure best approach

I use this SQL to get count for every group of type.
select
mytype, count(mytype)
from types1
group by 1
The result is 5 records with count for each type. I need to convert this to a stored procedure; should I write the above SQL using For...Select or should I return single value using Select...Where...Into 5 times for each type?
I will use the return counts to update a master table and types may increase in the future.
That depends on what you want out of the procedure:
If you want the same output as your select with five rows, use a FOR SELECT. You will get one row for each type and an associated count. This is probably the "standard" approach.
If however you want five output variables, one for each count of each type, you can use five queries of the form SELECT COUNT(1) FROM types1 WHERE mytype = 'type1' INTO :type1. Realize though that this will be five queries and you may be better off doing a single FOR SELECT query and looping through the returned rows in the procedure. Also note that if you at some point add a sixth type you will have to change this procedure to add the additional type.
If you want to query a single type, you can also do something like the following, which will return a single row with a single count for the type in the input parameter:
CREATE PROCEDURE GetTypeCount(
TypeName VARCHAR(256)
)
RETURNS (
TypeCount INTEGER
)
AS
BEGIN
SELECT COUNT(1)
FROM types1
WHERE mytype = :TypeName
INTO :TypeCount;
SUSPEND
END

Select statement within a cell in a database table

I have a basic database table. I would like to implement a functionallity that would allow to insert a select query within a random cell in the table. The result of this query would then be used as as any other cell of elementary type - in my case to compare it to an another value.
The problem is that I do not know in advance how those queries look like.
Here is an example. Say I have a an incoming parameter "score", which assumes some random integer values. I would like to see if the parameter "score" falls within the range defined between the values in Col1 and Col2, and if so happens, then to return the value in Col3.
Table1:
Col1 Col2 Col3
5 10 first row
10 15 second row
20 30 third row
* 50 forth row
* -> select avg(some_number) from Table2;
This random query can occur in any cell and is certain to return a single value. That is why I cannot use a simple JOIN statement.
Edit: Thanks Tim for suggesting to give an example.
You should look at CASE statements in SQL, and also at virtual or symbolic columns whose value is the result of an expression or function.

Query to retrieve rows where values are empty or numeric only

I need assistance with this. Assuming the folllowing table:
http://img820.imageshack.us/img820/6821/captureior.png
I need a SQL server query to select row 2 only (S1) and retrieve which item in the column(i.e. S1...S5) doesnt have k
That returns something like this:
S1
S2
T1
T2
T3
S3
S4
(I intend to bind the rows items to a listbox that)
Well, with plain vanilla SQL you have no built-in way to check if a given value is numeric or not. however, for your particular case you can simply check if the value is not null and doesn't contain k:
select * from YourTable where sr is not null and sr not like '%k%'
If there's other possible non numerical characters than k that can be in the table, your best bet is to make some stored procedure that checks each character of a given strig if it's numeric or not and use that