SQL condition for a join - sql

I've created an SQL query (Oracle) that is a join of 2 tables, and this table has entries related to users joining or leaving a particular instance.
So, let's say that the table looks something like:
+------------+--------+
| User_ID | State |
+------------+--------+
| 101 | Joined |
+------------+--------+
| 102 | Joined |
+------------+--------+
| 101 | Left |
+------------+--------+
As you can see, user 101 Joined, but then left. Is it possible to somehow specify that in case user left, then all entries related to this user are removed from the table (user ID is unique), but in case there is only entry saying that user Joined, then user will stay in the table?
I am new to SQL, my apologies if the question lacks some details, please feel free to ask for clarification.

To remove the records pertaining to users that have left, you might try the following:
DELETE FROM mytable m1
WHERE EXISTS ( SELECT 1 FROM mytable m2
WHERE m2.user_id = m1.user_id
AND m2.state = 'Left' );
Alternately (this might make things a bit more clear):
DELETE FROM mytable m1
WHERE m1.user_id IN ( SELECT m2.user_id
FROM mytable m2
WHERE m2.state = 'Left' );
Hope this helps.

You can get the list of ID that has the State "Left" and then delete those IDs
DELETE FROM tablename
WHERE user_id IN (SELECT user_id
FROM tablename
WHERE state = "left")

You can do something like this:
select t.*
from t
where not exists (select 1 from t t2 where t2.id = t.id and t.state = 'Left');
You can easily turn this to a delete:
delete t
where exists (select 1 from t t2 where t2.id = t.id and t.state = 'Left');

Related

Case Statement for Joined Table

I have two tables:
Account ID | A | B
-------------------
1 | x | y
2 | c | f
3 |...|...
the first table is a general account list. The second table is a list of documents on hand for each acct:
Account ID | Doctype
---------------------
1 | chrgoff
2 | dtpmnt
2 | chrgoff
3 | lstpmt
3 | suit
For the report I'm creating, I need to create a column in the first table which stores the value of a flag, where 'Y' indicates that the second table contains the docType 'chrgoff' for a given account number.
I tried doing this with the following case statement, but the query won't execute at all:
'chgoff' =
CASE
WHEN EXISTS(SELECT docType FROM table2 WHERE docType='chrgoff' and AccountID=table1.accountID)
THEN 'Y'
ELSE 'N'
END
I'm very new to T-SQL programming, so I would appreciate any help I could get! Let me know if I need to clarify anything. Thanks!
You code looks okay, but I would suggest:
(CASE WHEN EXISTS (SELECT docType FROM table2 t2 WHERE t2.docType = 'chrgoff' and t2.AccountID = table1.accountID)
THEN 'Y'
ELSE 'N'
END) as chgoff
The main differences are:
No single quotes on the column name. Only use single quotes for string and date constants.
Qualify the column references in the subquery. Don't depend on SQL's scoping rules. Be explicit.
As for as versus =. I prefer the former because it is standard SQL; = only assigns column aliases in SQL Server and related databases.
Alternate way - You can flag a record by joining both the tables with left outer join. I believe it would be faster approach than EXIST with subquery.
SQL -
select t1.*,
case when t2.account_id is not null then 'Y' else 'N' end as chgoff
from table1 t1
left join table2 t2 on t1.account_id = t2.account_id and t2.doctype = 'chrgoff'

Linking two Columns in the same table

I have the following columns in my table:
Title | Title Root
-------|--------------
A | null
B | A
C | D
D | null
E | null
F | E
I need to be able to have my query see that rows like B,C, and F have a value in Title_Root and display the corresponding title of that title_root. For example: B has Title_root = A. So then display the Title A. I don't want it to display B's title though.
I hope this makes sense. I just started doing queries.
Looks like a simple outer join:
select t1.title,
t2.title_root
from the_table t1
left join the_table t2 on t2.title_root = t1.title
Or if you only want to see one title:
select coalesce(t2.title_root, t1.title) as title
from the_table t1
left join the_table t2 on t2.title_root = t1.title
It seems like a simple update statement should do the trick:
UPDATE Table
SET title = title_root
WHERE title_root is not null
Hope this helps.

Updating a table using a different table

This is probably very simple but as I am an SQL noobie I do not want to get this wrong and destroy our database.
I am looking at updating a table based on what is in another table. in one table we have a list of users, the form they are in and their tutor. When the form is updated on the front end it does not change the tutor to the one who is related with that form. For example, we have changed the form to the new ones and the tutors below should now read Tom, Dick and Harry respectively:
Table 1
user | form | tutor
---------------------------------
a | 10Tom | Bill
b | 11Dick | Paul
c | 9Harry | Dave
We have another table which links up the respective forms to the correct tutors:
Table 2
form | tutor
-----------------------
10Tom | Tom
11Dick | Dick
9Harry | Harry
I am thinking the code should look like this, but I do not know if JOIN works in this situation:
UPDATE Table1
LEFT OUTER JOIN Table2
ON Table1.Form = Table2.Form
SET Table1.Tutor = Table2.Tutor
WHERE Table1.Form = Table2.Form
Can anyone give me some insight whether this will work? I have backed up the database so hopefully if I do break something I can recover it.
Thanks
Rob
In MySQL, you can express this as:
UPDATE Table1 t1 JOIN
Table2 t2
ON t1.Form = t2.Form
SET t1.Tutor = t2.Tutor;
In SQL Server or Postgres, you could do:
UPDATE Table1 t1 JOIN
SET t1.Tutor = t2.Tutor
FROM Table2 t2
WHERE t1.Form = t2.Form;
In any database, you should be able to do:
UPDATE Table1 JOIN
SET Tutor = (SELECT t2.Tutor
FROM Table2 t2
WHERE table1.Form = t2.Form
)
WHERE EXISTS (SELECT 1
FROM Table2 t2
WHERE table1.Form = t2.Form
);
this should work. I am assuming the requirement needs a left outer join.
UPDATE Table1
SET Table1.Tutor = Table2.Tutor
from Table2
where Table1.Form = Table2.Form;
You didn't specify the backend you are using but that syntax doesn't look right. Instead do it like:
UPDATE Table1
SET Table1.Tutor = Table2.Tutor
from table2
WHERE Table1.Form = Table2.Form;
Update Table1
SET tutor = t2.tutor
From Table1 t1
JOIN Table2 t2
on t1.form = t2.form

Unique Select Query into Table Sqlite3

I have the following database structure
Table 1
EventID | Person1 | Person2 | Person3 | ... | PersonN
Table 2
Person | Height | Weight
Now I would like a query that for a given EventID (which is unique) returns the persons involved along with their Height and Weight.
I was thinking of creating some sort of temporary table along the lines of
CREATE TEMP TABLE t AS
SELECT Person1, Person2, Person3, ..., PersonN FROM Table1 WHERE EVENTID = ?
and then joining the temporary table t with table2 but of course this doesn't work as what I want is the transpose of t.
How would I go about doing this?
If you are given the event id, you can use exists:
select t2.*
from table2 t2
where exists (select 1
from table1 t1
where t2.person in (t1.person1, t1.person2, t1.person3) and
t1.eventid = $eventid
);
Your data structure, however, is not very suitable for scaling purposes. The problem data structure would have an EventPersons table, with one column for EventId and one column per PersonId.
select t2.person, t2.height, t2.weight
from table2 t2
join
(select person1 as person,event_id as person from table1
union select person2,event_id from table1..
select personN,event_id from table1) t3
on t3.person = t2.person
where t3.event_id = ?
This is the more generic approach i can think of. But as the comments mentions you should consider changing the table structure.

Creating a SQL column based on the value of another column in the same table

I must not be using the right Google foo to find the correct answer.
I have a table that looks like the following:
ID Parent  Status   Name
1              NULL     0              Root 2             1              0              Group 1
3             6              400         WINXP32
4              2              400         WIN7
5              2              400         WIN2K8
6              1              0              Group 2
The 'name' column contains both group names and machine names. Groups have a 'Status' of 0.
How would I create a SQL statement to display (not modify the database) a column called 'Group' based on the logic that the 'Parent' column holds the 'ID' of its parent.
Somehow I can figure out how to join data from other tables but I cant figure this out...
-- Update: I forgot to show an example of the output I'm looking for, in a perfect world I would get the following..
ID | Group | Status | Name
3 | Group 2 | 400 | WINXP32
4 | Group 1 | 400 | WIN7
5 | Group 1 | 400 | WIN2K8
I would (i think) filter out the groups from the output by doing a where status > 0
Thanks everyone for the quick feedback !
Try like thsi
SELECT ID,
CASE WHEN STATUS = 0 THEN (SELECT Root WHERE Parent = ID)
END [Group]
Status,
Name
FROM TABLE1
WHERE STATUS <> 0
Do you mean something like this (Self join in SQL standard)?
If it's possible that you have records with missing Parent ID:
select t1.name,
t2.name as "Group"
from tab t1
left join tab t2
on t1.parent = t2.id
where t1.status > 0;
If Parent ID is always present, you can use an inner join:
select t1.name,
t2.name as "Group"
from tab t1, tab t2
where t1.parent = t2.id
and t1.status > 0;
Otherwise, please can you explain what you need?
I think your main problem is to use the same table twice. This is achieved using different aliases like Corrado Piola explained it.
select t1.name, t2.name from mytab t1, mytab t2 where ...
Now t1 and t2 are acting like different tables.
Select
m.id,g.Name,m.Status,m.Name
from
table1 M,
table2 G
where
m.Status >0
and g.Status = 0
and m.Parent = g.id