How to update multiple SQL records with same condition - sql

I have this table
id | attributeId | value
--------------------------
1 | 1 | abc
2 | 1 | def
I want to update this table where "attributeId = 1" with these values {"123", "456", "789"} so the table will look like this:
id | attributeId | value
--------------------------
1 | 1 | 123
2 | 1 | 456
3 | 1 | 789
My idea is to delete all the old records and then add new records but I think there are more better method to do this. Is there any better way?

Consider following:
Alter table Your_Table DROP COLUMN VALUE
CREATE TABLE TEMP (ID INT, VALUE VARCHAR(3));
INSERT INTO TMP VALUES (1, '123'), (1, '456'), (1, '789');
SELECT A.*, B.VALUE INTO NEW_TABLE FROM Your_Table a join TMP b on a.id = b.id;
The new_table will have your requested structure.

If your goal is to replace the table, then just delete all the rows and insert new values:
truncate table t;
insert into t (id, attributeId, value)
values (1, 1, 123),
(2, 1, 456),
(3, 1, 789);
If you don't want the original rows that are not in the new data, I would not bother trying to figure out the differences between the tables. The truncate should be pretty fast and bulk updates are usually faster than update some records and insert some others.

Related

Insert value of one column from one table to another table based on where condition

I have one question . Suppose there is one table rules in which column department, action ,left_source and right_source,left_source_id,right_source_id is there .Another table is source table where column is name,I'd .
Now i have to insert rules to rule table but in left_source_id and right_source_id i have to insert value from source table based on I'd column . I need some immediate help .
(Source table column I'd contains all the name of left_source and right_source )
Insert Select...union all..select for example
drop table if exists t,t1;
create table t(id int,leftsource varchar(1),rightsource varchar(1));
create table t1(id int,val varchar(1));
insert into t1 values
(1,'l'),(2,'r');
insert into t
select id,val,null from t1 where id = 1
union all
select id,null,val from t1 where id = 2
select * from t;
+------+------------+-------------+
| id | leftsource | rightsource |
+------+------------+-------------+
| 1 | l | NULL |
| 2 | NULL | r |
+------+------------+-------------+
2 rows in set (0.001 sec)

SQLite query - filter name where each associated id is contained within a set of ids

I'm trying to work out a query that will find me all of the distinct Names whose LocationIDs are in a given set of ids. The catch is if any of the LocationIDs associated with a distinct Name are not in the set, then the Name should not be in the results.
Say I have the following table:
ID | LocationID | ... | Name
-----------------------------
1 | 1 | ... | A
2 | 1 | ... | B
3 | 2 | ... | B
I'm needing a query similar to
SELECT DISTINCT Name FROM table WHERE LocationID IN (1, 2);
The problem with the above is it's just checking if the LocationID is 1 OR 2, this would return the following:
A
B
But what I need it to return is
B
Since B is the only Name where both of its LocationIDs are in the set (1, 2)
You can try to write two subquery.
get count by each Name
get count by your condition.
then join them by count amount, which means your need to all match your condition count number.
Schema (SQLite v3.17)
CREATE TABLE T(
ID int,
LocationID int,
Name varchar(5)
);
INSERT INTO T VALUES (1, 1,'A');
INSERT INTO T VALUES (2, 1,'B');
INSERT INTO T VALUES (3, 2,'B');
Query #1
SELECT t2.Name
FROM
(
SELECT COUNT(DISTINCT LocationID) cnt
FROM T
WHERE LocationID IN (1, 2)
) t1
JOIN
(
SELECT COUNT(DISTINCT LocationID) cnt,Name
FROM T
WHERE LocationID IN (1, 2)
GROUP BY Name
) t2 on t1.cnt = t2.cnt;
| Name |
| ---- |
| B |
View on DB Fiddle
You can just use aggregation. Assuming no duplicates in your table:
SELECT Name
FROM table
WHERE LocationID IN (1, 2)
GROUP BY Name
HAVING COUNT(*) = 2;
If Name/LocationID pairs can be duplicated, use HAVING COUNT(DISTINCT LocationID) = 2.

Insert data into two columns only if not duplicate

I have a table user_interests with id(AUTO_INC), user_id, user_interest columns.
I want a easy way to insert data into user_id and user_interest without duplicate entries.
E.g. if I have a table like this before.
+------------------------------+
| ID | user_id | user_interest |
+------------------------------+
| 1 | 2 | Music |
| 2 | 2 | Swimming |
+------------------------------+
If I now insert into table (user_id, user_interest) values ((2, Dance),(2, Swimming), I only need (2,dance) entry to be inserted - not (2, swimming) since (2, swimming) already exists in the table.
I have seen upsert commands, and have also tried creating a command like below but it doesn't work.
INSERT INTO `user_interests`( `user_id`,`interest` )
VALUES ("2","Music")
WHERE (SELECT COUNT(`interest`) FROM `user_interests`
WHERE `interest` = "Music" AND `user_id` = "2"
Having COUNT(`interest`) <=0 )
Use NOT EXISTS method :
INSERT INTO your_table (user_id ,user_interest )
SELECT #userId , #UserIntreset
WHERE NOT EXISTS(SELECT 1 FROM your_table user_id = #userid AND user_interest
= #userinterest )
Or Create unique constraint in your table,
ALTER TABLE your_table
ADD CONSTRAINT Constraint_Name UNIQUE (Column_Name1,Column_Name2)

SQL select in from a field containing comma separated keys

Is there a way I can construct a SQL statement that will help me retrieve active records based on status then references to oldids stored in another field?
Let's say I want to join the data below to another table. For ID=4, it is meant to imply that IDs 1,3 and 4 are combined and the surviving record is 4.
So when I want to join it with another table, how can I have scvid 104 be linked to transactions of IDs 1,3, and 4?
select *
from tbl
where scvid in (id, oldids)?
Sample data:
scvid id oldid status
------------------------------
101 1 NULL 0
102 2 NULL 1
103 3 NULL 0
104 4 [1,3] 1
You didn't mention your DB system. Here is the solution for SQL Server (TSQL). You can use it also in another RDBMS with minor changes
SELECT
t1.*, t2.scvid as NEWID
FROM
tbl t1
JOIN
tbl t2 ON
-- first case: if the record is main with [1,3] we link it to the the self
(t1.scvid = t2.scvid) AND (t2.oldid IS NOT NULL)
OR
-- second case: we bulid ",1,3," from "[1,3]"
-- then we get condition ",1,3," LIKE "%,id,%"
-- for the id = 1 and 3 it's TRUE
(REPLACE(REPLACE(t2.oldid,'[',','),']',',')
LIKE '%,'+CAST(t1.id as VARCHAR(100))+',%')
AND (t1.oldid IS NULL)
RESULT:
scvid id oldid status NEWID
101 1 NULL 0 104
103 3 NULL 0 104
104 4 [1,3] 1 104
This output new column NEWID for the old Id in this record so you can JOIN or use it in another way.
For Postgres you can do this by converting the comma separated list into an array.
Something like this:
Sample setup:
create table some_table (id integer);
insert into some_table values (4), (6), (8);
create table service (svcid integer, id integer, oldid text, status integer);
insert into service
values
(101, 1, NULL , 0),
(102, 2, NULL , 1),
(103, 3, NULL , 0),
(104, 4, '1,3', 1);
To get all rows from some_table where the id is either the id column of the service table or any of those in the oldid column you can use:
select *
from some_table st
join (
select svcid, id, oldid, status, string_to_array(s.oldid, ',')::int[]||id as all_ids
from service s
) s on st.id = any(s.all_ids)
This returns:
id | svcid | id | oldid | status | all_ids
---+-------+----+-------+--------+--------
4 | 104 | 4 | 1,3 | 1 | {1,3,4}
This works on SQL Server.
Since that LIKE syntax supports a negative character class as [^0-9].
select
old.scvid as old_scvid, old.id as old_id,
new.scvid as new_scvid, new.id as new_id, new.oldid as new_oldids
from tbl new
left join tbl old
on (old.status = 0 and new.oldid like concat('%[^0-9]',old.id,'[^0-9]%'))
where new.status = 1
and new.oldid is not null
To bad that the table doesn't have a "newid" field, instead of that "oldid" with a range.
That would make it a lot easier to join.

How to the write SQL to show the data in my case in Oracle?

I have a table like this -
create table tbl1
(
id number,
role number
);
insert into tbl1 values (1, 1);
insert into tbl1 values (2, 3);
insert into tbl1 values (1, 3);
create table tbl2
(
role number,
meaning varchar(50)
);
insert into tbl2 values (1, 'changing data');
insert into tbl2 values (2, 'move file');
insert into tbl2 values (3, 'dance');
I want the sql result like the following -
id role_meaning is_permitted
1 changing data yes
1 move file no
1 dance yes
2 changing data no
2 move file no
2 dance yes
Please help how can I do this? I have tried several methods but not sure how to do this.
You can use partitioned outer join here.
SQL Fiddle
Query 1:
select tbl1.id,
tbl2.meaning,
case when tbl1.role is NULL then 'no' else 'yes' end is_permitted
from tbl1
partition by (id) right outer join tbl2
on tbl1.role = tbl2.role
order by tbl1.id, tbl2.role
Results:
| ID | MEANING | IS_PERMITTED |
|----|---------------|--------------|
| 1 | changing data | yes |
| 1 | move file | no |
| 1 | dance | yes |
| 2 | changing data | no |
| 2 | move file | no |
| 2 | dance | yes |