Adjusting composite key when deleting database elements in SQL - sql

Consider the following table T
------------------------------
| CountryID | Obs | Event |
------------------------------
| 1 | 1 | 10 |
| 1 | 2 | 20 |
| 1 | 3 | 30 |
| 2 | 1 | 20 |
| 2 | 2 | 30 |
| 2 | 3 | 10 |
| 3 | 1 | 30 |
| 3 | 2 | 10 |
| 3 | 3 | 20 |
------------------------------
I would like to delete all rows such that Event = 20 however I would then like to update the Obs so that they were still in incremental order from 1 with a difference of 1.
For example if I run SELECT * FROM T WHERE Event != 20, I would get
------------------------------
| CountryID | Obs | Event |
------------------------------
| 1 | 1 | 10 |
| 1 | 3 | 30 |
| 2 | 2 | 30 |
| 2 | 3 | 10 |
| 3 | 1 | 30 |
| 3 | 2 | 10 |
------------------------------
but instead I want
------------------------------
| CountryID | Obs | Event |
------------------------------
| 1 | 1 | 10 |
| 1 | 2 | 30 |
| 2 | 1 | 30 |
| 2 | 2 | 10 |
| 3 | 1 | 30 |
| 3 | 2 | 10 |
------------------------------
what query do I need to achieve this?

First, in SQLite, there is a pseudo-column called rowid that uniquely identifies each row. You can do what you want by using a correlated subquery:
update t
set obs = (select count(*)
from t t2
where t2.countryid = t.countryid and t2.rowid <= t.rowid
);
That said, this is quite inefficient and shouldn't be run on anything other than baby tables. If this is an operation that you regularly want to do, you might consider a more powerful database than SQLite.

Related

Update where value pair matches in SQL

I need to update this table:
Centers:
+-----+------------+---------+--------+
| id | country | process | center |
+-----+------------+---------+--------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 1 |
| 3 | 1 | 3 | 1 |
| 4 | 2 | 1 | 1 |
| 5 | 2 | 2 | 1 |
| 6 | 2 | 3 | 1 |
| 7 | 3 | 1 | 1 |
| 8 | 3 | 2 | 1 |
| 9 | 3 | 3 | 1 |
+-----+------------+---------+--------+
During a selection process I retrieve two tempTables:
TempCountries:
+-----+------------+
| id | country |
+-----+------------+
| 1 | 1 |
| 2 | 3 |
+-----+------------+
And TempProcesses:
+-----+------------+
| id | process |
+-----+------------+
| 1 | 2 |
| 2 | 3 |
+-----+------------+
In a subquery I get all possible combinations of the values:
SELECT TempCountries.countryId, TempProcesses.processesId FROM TempCenterCountries,TempCenterProcesses
This returns:
+-----+------------+---------+
| id | country | process |
+-----+------------+---------+
| 1 | 1 | 2 |
| 2 | 1 | 3 |
| 3 | 3 | 2 |
| 4 | 3 | 3 |
+-----+------------+---------+
During the selection process the user chooses a center for these combinations. Let’s say center = 7.
Now I need to update the center value in the Centers table where the combinations of the subquery are present.
So,
UPDATE Centers SET center = 7 WHERE ?
So I get:
+-----+------------+---------+--------+
| id | country | process | center |
+-----+------------+---------+--------+
| 1 | 1 | 1 | 1 |
| 2 | 1 | 2 | 7 |
| 3 | 1 | 3 | 7 |
| 4 | 2 | 1 | 1 |
| 5 | 2 | 2 | 1 |
| 6 | 2 | 3 | 1 |
| 7 | 3 | 1 | 1 |
| 8 | 3 | 2 | 7 |
| 9 | 3 | 3 | 7 |
+-----+------------+---------+--------+
Not all sql implementations let you have a from clause when using update. Fortunately in your case since you're doing a Cartesian product to get all the combinations it implies that you don't have any constraints between the two values.
UPDATE Centers
SET center = 7
WHERE country IN (SELECT countryId FROM TempCountries)
AND process IN (SELECT processId FROM TempCenterProcesses)
Try if this standard sql,
Update Centers
set center = 7
where country in (select country from TempCenterCountries)
and process in (select process from TempCenterProcesses)
You need to have exact match of country as well as process before you run the update query. So, something like below query would help you achieve that. Basically update the column if there exists a record
WITH (SELECT TempCountries.countryId, TempProcesses.processesId
FROM TempCenterCountries,
TempCenterProcesses) AS TempTables,
UPDATE Centers
SET center = 7
WHERE EXISTS (SELECT 1
FROM TempTables tmp
WHERE country = tmp.countryId and process = tmp.processesId
);
The idea is to update the record if both country and process matches with the one you have already fetched in temporary table.
Use update join -
For Sql Server
update c set SET center = 7 from Centers c
join
(SELECT TempCountries.countryId, TempProcesses.processesId FROM TempCenterCountries join TempCenterProcesses
)A on c.countryid=A.countryid and c.processesId=A.processId
For Mysql -
update Centers c
join
(SELECT TempCountries.countryId, TempProcesses.processesId FROM TempCenterCountries join TempCenterProcesses
)A on c.countryid=A.countryid and c.processesId=A.processId
set SET center = 7

how to check whether an element in the row exists somewhere in other column but not the same row

I have a SQL table as following
--------------------------
| REPO | USER | FOLLOWER |
--------------------------
| A | 1 | 3 |
| A | 2 | 4 |
| A | 3 | 6 |
| B | 2 | 7 |
| B | 4 | 2 |
| C | 5 | 3 |
| C | 2 | 6 |
| C | 6 | 5 |
--------------------------
Now, I want to only those rows where USER follows another USER for
same REPO.
i.e. I want rows where elements in FOLLOWER is also in USER for same
REPO.
OUTPUT should be like...
--------------------------
| REPO | USER | FOLLOWER |
--------------------------
| A | 1 | 3 |
| B | 4 | 2 |
| C | 6 | 5 |
| C | 2 | 6 |
--------------------------
Thank You :)
One simple method uses exists:
select t.*
from t
where exists (select 1 from t t2 where t2.repo = t.repo and t2.follower = t.user);
Shouldn't the output actually be as follows, i.e. 4 rows?
--------------------------
| REPO | USER | FOLLOWER |
--------------------------
| A | 1 | 3 |
| B | 4 | 2 |
| C | 6 | 5 |
| C | 2 | 6 |
--------------------------

Update columns based on record count and count total

I need some help writing a script to update a table.
The table has the following:
| StudentID | Name | Record | Label |
| 1 | Ed | 1 | 1 |
| 1 | Ed | 1 | 1 |
| 1 | Ed | 1 | 1 |
| 1 | Ed | 1 | 1 |
| 2 | Bob | 1 | 1 |
| 2 | Bob | 1 | 1 |
| 2 | Bob | 1 | 1 |
| 2 | Bob | 1 | 1 |
I would like to update the Record and Label columns, so that the query would increment the Record column from 1 to n for the same StudentId. The Label column would also need to be updated to display the record # of total number of records for that StudentId.
The result for Ed should be:
| StudentID | Name | Record | Label |
| 1 | Ed | 1 | 1 of 4 |
| 1 | Ed | 2 | 2 of 4 |
| 1 | Ed | 3 | 3 of 4 |
| 1 | Ed | 4 | 4 of 4 |
Hoping someone can help me with this.

SQL compare multiple rows or partitions to find matches

The database I'm working on is DB2 and I have a problem similar to the following scenario:
Table Structure
-------------------------------
| Teacher Seating Arrangement |
-------------------------------
| PK | seat_argmt_id |
| | teacher_id |
-------------------------------
-----------------------------
| Seating Arrangement |
-----------------------------
|PK FK | seat_argmt_id |
|PK | Row_num |
|PK | seat_num |
|PK | child_name |
-----------------------------
Table Data
------------------------------
| Teacher Seating Arrangement|
------------------------------
| seat_argmt_id | teacher_id |
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 2 |
------------------------------
---------------------------------------------------
| Seating Arrangement |
---------------------------------------------------
| seat_argmt_id | row_num | seat_num | child_name |
| 1 | 1 | 1 | Abe |
| 1 | 1 | 2 | Bob |
| 1 | 1 | 3 | Cat |
| | | | |
| 2 | 1 | 1 | Abe |
| 2 | 1 | 2 | Bob |
| 2 | 1 | 3 | Cat |
| | | | |
| 3 | 1 | 1 | Abe |
| 3 | 1 | 2 | Cat |
| 3 | 1 | 3 | Bob |
| | | | |
| 4 | 1 | 1 | Abe |
| 4 | 1 | 2 | Bob |
| 4 | 1 | 3 | Cat |
| 4 | 2 | 2 | Dan |
---------------------------------------------------
I want to see where there are duplicate seating arrangements for a teacher. And by duplicates I mean where the row_num, seat_num, and child_name are the same among different seat_argmt_id for one teacher_id. So with the data provided above, only seat id 1 and 2 are what I would want to pull back, as they are duplicates on everything but the seat id. If all the children on the 2nd table are exact (sans the primary & foreign key, which is seat_argmt_id in this case), I want to see that.
My initial thought was to do a count(*) group by row#, seat#, and child. Everything with a count of > 1 would mean it's a dupe and = 1 would mean it's unique. That logic only works if you are comparing single rows though. I need to compare multiple rows. I cannot figure out a way to do it via SQL. The solution I have involves going outside of SQL and works (probably). I'm just wondering if there is a way to do it in DB2.
Does this do what you want?
select d.teacher_id, sa.row_num, sa.seat_num, sa.child_name
from seatingarrangement sa join
data d
on sa.seat_argmt_id = d.seat_argmt_id
group by d.teacher_id, sa.row_num, sa.seat_num, sa.child_name
having count(*) > 1;
EDIT:
If you want to find two arrangements that are the same:
select sa1.seat_argmt_id, sa2.seat_argmt_id
from seatingarrangement sa1 join
seatingarrangement sa2
on sa1.seat_argmt_id < sa2.seat_argmt_id and
sa1.row_num = sa2.row_num and
sa1.seat_num = sa2.seat_num and
sa1.child_name = sa2.child_name
group by sa1.seat_argmt_id, sa2.seat_argmt_id
having count(*) = (select count(*) from seatingarrangement sa where sa.seat_argmt_id = sa1.seat_argmt_id) and
count(*) = (select count(*) from seatingarrangement sa where sa.seat_argmt_id = sa2.seat_argmt_id);
This finds the matches between two arrangements and then verifies that the counts are correct.

Ask about query in sql server

i have table like this:
| ID | id_number | a | b |
| 1 | 1 | 0 | 215 |
| 2 | 2 | 28 | 8952 |
| 3 | 3 | 10 | 2000 |
| 4 | 1 | 0 | 215 |
| 5 | 1 | 0 |10000 |
| 6 | 3 | 10 | 5000 |
| 7 | 2 | 3 |90933 |
I want to sum a*b where id_number is same, what the query to get all value for every id_number? for example the result is like this :
| ID | id_number | result |
| 1 | 1 | 0 |
| 2 | 2 | 523455 |
| 3 | 3 | 70000 |
This is a simple aggregation query:
select id_number, sum(a*b)
from t
group by id_number
I'm not sure what the first column is for.