How to delete multiple rows in SQL where id = (x to y) - sql

I am trying to run a SQL query to delete rows with id's 163 to 265 in a table
I tried this to delete less number of rows
DELETE FROM `table` WHERE id IN (264, 265)
But when it comes to delete 100's of rows at a time, Is there any query similar to above method
I am also trying to use this kind of query but failed to execute it
DELETE FROM `table` WHERE id IN (SELECT * FROM table WHERE id = )
Please tell me the query to do the above action...

If you need to delete based on a list, you can use IN:
DELETE FROM your_table
WHERE id IN (value1, value2, ...);
If you need to delete based on the result of a query, you can also use IN:
DELETE FROM your_table
WHERE id IN (select aColumn from ...);
(Notice that the subquery must return only one column)
If you need to delete based on a range of values, either you use BETWEEN or you use inequalities:
DELETE FROM your_table
WHERE id BETWEEN bottom_value AND top_value;
or
DELETE FROM your_table
WHERE id >= a_value AND id <= another_value;

You can use BETWEEN:
DELETE FROM table
where id between 163 and 265

Please try this:
DELETE FROM `table` WHERE id >=163 and id<= 265

SELECT * FROM your_table ORDER BY DESC
Get the range that you want to delete Ex: 3 to 10
DELETE FROM your_table
WHERE id BETWEEN 3 AND 10;
Make sure to add min value fist in BETWEEN Clause

CREATE PROC [dbo].[sp_DELETE_MULTI_ROW]
#CODE XML
,#ERRFLAG CHAR(1) = '0' OUTPUT
AS
SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
DELETE tb_SampleTest
WHERE
CODE IN(
SELECT Item.value('.', 'VARCHAR(20)')
FROM #CODE.nodes('RecordList/ID') AS x(Item)
)
IF ##ROWCOUNT = 0
SET #ERRFLAG = 200
SET NOCOUNT OFF
Get string value delete
<RecordList>
<ID>1</ID>
<ID>2</ID>
</RecordList>

Related

Lock multiple rows but get only one row as returned result

I need lock multiple rows, but get only one row as returned result, for example lock users: 2,4 and 7, but only get data for user where id = 2
Well, as I understood, there is 2 possible ways:
1) run two different queries:
-- get user data and lock that row
SELECT some_column FROM users WHERE id = 2 FOR UPDATE INTO my_var;
-- just lock another rows
SELECT some_column FROM users WHERE id IN(4,7) FOR UPDATE;
2) Use one query, with CTE and "fake" update, something like:
WITH t AS(
UPDATE users
SET some_column = some_column
WHERE id IN(2,4,7)
returning some_column
)
SELECT some_column FROM t WHERE id = 2
INTO my_var;
So, which way is more appropriate? or may be there are even better methods ?
I would use CTE, but without real update:
sample table and data:
t=# create table su(i int);
CREATE TABLE
t=# insert into su values(1),(2),(3),(4);
INSERT 0 4
select for update three key returning one key:
begin;
with l as (select * from su where i in (1,2,4) for update)
select * from l where i = 2;
BEGIN
i
---
2
(1 row)
attempting to:
begin; update su set i=i where i = 1;
in a different session waits for the transaction above to complete, while with where i = 1 does not. and SQL in first transaction returns only where i = 2
The second solution is worse as it executes idle updates.
If you want to do that in a single query, use SELECT ... FOR UPDATE:
WITH t AS (
SELECT id, some_column
FROM users
WHERE id IN(2,4,7)
FOR UPDATE
)
SELECT some_column
FROM t
WHERE id = 2;

Insert row over existing row, move rows down

I'm trying to insert a new row in the middle of a sql table and move all other rows first to make space for it.
I've tried
setting id=id+1,
but that gives me an error(obviously) because the row id+1 exists already, so this only works for going in the other direction so id=id-1.
What is the correct solution then?
To do the stuff, you should update you table from the end:
UPDATE `table` SET `id`=`id`+1 WHERE `id`>$value ORDER BY `id` DESC
Where $value is your value
You could try something like this:
UPDATE table_name SET id = id + 1 WHERE id >= your_id_value ORDER BY id DESC;
INSERT INTO table_name(..., id, ...) VALUES(..., your_id_value, ...)

Fastest check if row exists in PostgreSQL

I have a bunch of rows that I need to insert into table, but these inserts are always done in batches. So I want to check if a single row from the batch exists in the table because then I know they all were inserted.
So its not a primary key check, but shouldn't matter too much. I would like to only check single row so count(*) probably isn't good, so its something like exists I guess.
But since I'm fairly new to PostgreSQL I'd rather ask people who know.
My batch contains rows with following structure:
userid | rightid | remaining_count
So if table contains any rows with provided userid it means they all are present there.
Use the EXISTS key word for TRUE / FALSE return:
select exists(select 1 from contact where id=12)
How about simply:
select 1 from tbl where userid = 123 limit 1;
where 123 is the userid of the batch that you're about to insert.
The above query will return either an empty set or a single row, depending on whether there are records with the given userid.
If this turns out to be too slow, you could look into creating an index on tbl.userid.
if even a single row from batch exists in table, in that case I
don't have to insert my rows because I know for sure they all were
inserted.
For this to remain true even if your program gets interrupted mid-batch, I'd recommend that you make sure you manage database transactions appropriately (i.e. that the entire batch gets inserted within a single transaction).
INSERT INTO target( userid, rightid, count )
SELECT userid, rightid, count
FROM batch
WHERE NOT EXISTS (
SELECT * FROM target t2, batch b2
WHERE t2.userid = b2.userid
-- ... other keyfields ...
)
;
BTW: if you want the whole batch to fail in case of a duplicate, then (given a primary key constraint)
INSERT INTO target( userid, rightid, count )
SELECT userid, rightid, count
FROM batch
;
will do exactly what you want: either it succeeds, or it fails.
If you think about the performace ,may be you can use "PERFORM" in a function just like this:
PERFORM 1 FROM skytf.test_2 WHERE id=i LIMIT 1;
IF FOUND THEN
RAISE NOTICE ' found record id=%', i;
ELSE
RAISE NOTICE ' not found record id=%', i;
END IF;
as #MikeM pointed out.
select exists(select 1 from contact where id=12)
with index on contact, it can usually reduce time cost to 1 ms.
CREATE INDEX index_contact on contact(id);
SELECT 1 FROM user_right where userid = ? LIMIT 1
If your resultset contains a row then you do not have to insert. Otherwise insert your records.
select true from tablename where condition limit 1;
I believe that this is the query that postgres uses for checking foreign keys.
In your case, you could do this in one go too:
insert into yourtable select $userid, $rightid, $count where not (select true from yourtable where userid = $userid limit 1);

I want to leave always one record if table record count = 1 with SQL

I can delete records with this SQL clause,
DELETE FROM TABLE WHERE ID = 2
I need to always leave one record if table count = 1 even if "ID=2". How can I do this?
Add a WHERE clause to ensure there's more than one row:
DELETE FROM TABLE
WHERE ID = 2
AND (SELECT COUNT(*) FROM TABLE) > 1
Untested, but something in the lines of this might work?
DELETE FROM TABLE WHERE ID = 2 LIMIT (SELECT COUNT(*)-1 FROM TABLE WHERE ID=2);
Maybe add in an if-statement to ensure count is above 1.
Simple way is to disallow any delete that empties the table
CREATE TRIGGER TRG_MyTable_D FOR DELETE
AS
IF NOT EXISTS (SELECT * FROM MyTable)
ROLLBACK TRAN
GO
More complex, what if you do this multirow delete that empties the table?
DELETE FROM TABLE WHERE ID BETWEEN 2 AND 5
so, randomly repopulate from what you just deleted
CREATE TRIGGER TRG_MyTable_D FOR DELETE
AS
IF NOT EXISTS (SELECT * FROM MyTable)
INSERT mytable (col2, col2, ..., coln)
SELECT TOP 1 col2, col2, ..., coln FROM INSERTED --ORDER BY ??
GO
However, the requirement is a bit dangerous and vague. In English, OK, "always have at least one row in the table", but in practice "which row?"

Updating a table within a select statement

Is there any way to update a table within the select_expr part of a mysql select query. Here is an example of what I am trying to achieve:
SELECT id, name, (UPDATE tbl2 SET currname = tbl.name WHERE tbl2.id = tbl.id) FROM tbl;
This gives me an error in mysql, but I dont see why this shouldn't be possible as long as I am not changing tbl.
Edit:
I will clarify why I cant use an ordinary construct for this.
Here is the more complex example of the problem which I am working on:
SELECT id, (SELECT #var = col1 FROM tbl2), #var := #var+1,
(UPDATE tbl2 SET col1 = #var) FROM tbl WHERE ...
So I am basically in a situation where I am incrementing a variable during the select statement and want to reflect this change as I am selecting the rows as I am using the value of this variable during the execution. The example given here can probably be implemented with other means, but the real example, which I wont post here due to there being too much unnecessary code, needs this functionality.
If your goal is to update tbl2 every time you query tbl1, then the best way to do that is to create a stored procedure to do it and wrap it in a transaction, possibly changing isolation levels if atomicity is needed.
You can't nest updates in selects.
What results do you want? The results of the select, or of the update.
If you want to update based on the results of a query you can do it like this:
update table1 set value1 = x.value1 from (select value1, id from table2 where value1 = something) as x where id = x.id
START TRANSACTION;
-- Let's get the current value
SELECT value FROM counters WHERE id = 1 FOR UPDATE;
-- Increment the counter
UPDATE counters SET value = value + 1 WHERE id = 1;
COMMIT;