Updating the column that the table was joined on - sql

I need to update a column that two tables were joined on and I'm having a difficult time wrapping my head around it. This is for SQL Server. Loose example below...
User
ID | Name | GroupID |
---------------------
1 | Bob | 100 |
2 | Alex | 300 |
3 | Sara | 300 |
Group
ID | Name |
----------------
100 | Produce |
200 | Cashier |
300 | Stocker |
GroupID is a foreign key to the Group table and they are being joined on that. I HAVE to update the GroupID column in User based on the Name column in Group. For example, I want Alex and Sara to change from 'Stocker' to 'Cashier'. My solution is below, but it doesn't seem to work.
UPDATE User
SET User.GroupID = G.ID
FROM User U
JOIN Group G ON U.GroupID = G.ID
WHERE User = 'Sara' OR User = 'Alex'
Expected Result
User
ID | Name | GroupID |
---------------------
1 | Bob | 100 |
2 | Alex | 200 |
3 | Sara | 200 |

You don't need and updated with join ..
but you could use a subquery for get the expected id from group
update user
set User.GroupID = (select id
from group where name = 'Cashier )
where User = 'Sara' OR User = 'Alex'

Related

SQL check if a record has a reference from another table and if so do something

I have two tables, users and friendships
id | name | password
-------------------------
1 | Dave | 1234
-------------------------
2 | John | abcd
-------------------------
3 | Bob | xyz
-------------------------
and the friendships
friend_one | friend_two | status
-------------------------------------
1 | 1 | me
-------------------------------------
2 | 2 | me
-------------------------------------
3 | 3 | me
------------------------------------
1 | 2 | pending
-------------------------------------
3 | 1 | active
Now whenever a user logged in to the system, I need to fetch all the users in the database, also I need to add an extra column to the result from the select query, which shows the friendship status with currently logged in user.
For example, user id 1 , Dave logged in to the system and request for users list, select query should be output as below,
id | name | password | friend_status
------------------------------------------
1 | Dave | 1234 | me
------------------------------------------
2 | John | abcd | pending
------------------------------------------
3 | Bob | xyz | active
------------------------------------------
When the user id 2, John logged in to the system, he need to get the below table,
id | name | password | friend_status
------------------------------------------
1 | Dave | 1234 | pending
------------------------------------------
2 | John | abcd | me
------------------------------------------
3 | Bob | xyz | null
------------------------------------------
Is this even possible ? I tried to join tables and use a nested query
For example, with the below query I can get all the friendships for the currently logged in user,
select * from friendships
where friend_one = 2 or friend_two = 2
But I don't understand what to do next. I tried to put this as a nested query of the main select query and tried to join tables but I'm not getting what I wanted.
Can anyone give me an idea?
You need to CROSS JOIN the list of id values from users with the users table to get all distinct pairs of id values, then LEFT JOIN that to the friendships table to get the friend status for each user:
SELECT u1.id, u.name, u.password,
f.status
FROM users u
CROSS JOIN (SELECT DISTINCT id
FROM users) u1
LEFT JOIN friendships f ON f.friend_one = u.id AND f.friend_two = u1.id
OR f.friend_one = u1.id AND f.friend_two = u.id
ORDER BY u1.id, u.id
Output:
id name password status
1 Dave 1234 me
1 John abcd pending
1 Bob xyz active
2 Dave 1234 pending
2 John abcd me
2 Bob xyz (null)
3 Dave 1234 active
3 John abcd (null)
3 Bob xyz me
Demo on SQLFiddle
To get a specific user, just add WHERE u1.id = ? before the ORDER BY clause.

Join Lookup from 1 table to multiple columns

How do I link 1 table with multiple columns in another table without using mutiple JOIN query?
Below is my scenario:
I have table User with ID and Name
User
+---------+------------+
| Id | Name |
+---------+------------+
| 1 | John |
| 2 | Mike |
| 3 | Charles |
+---------+------------+
And table Product with multiple columns, but just focus on 2 columns CreateBy And ModifiedBy
+------------+-----------+-------------+
| product_id | CreateBy | ModifiedBy |
+------------+-----------+-------------+
| 1 | 1 | 3 |
| 2 | 1 | 3 |
| 3 | 2 | 3 |
| 4 | 2 | 1 |
| 5 | 2 | 3 |
+------------+-----------+-------------+
With normal JOIN, i will need to do 2 JOIN:
SELECT p.Product_id,
u1.Name AS CreateByName,
u2.Name AS ModifiedByName
FROM Product p
JOIN USER user u1 ON p.CreateBy = u1.Id,
JOIN USER user u2 ON p.ModifiedBy = u2.Id
to come out result
+------------+---------------+-----------------+
| product_id | CreateByName | ModifiedByName |
+------------+---------------+-----------------+
| 1 | John | Charles |
| 2 | John | Charles |
| 3 | Mike | Charles |
| 4 | Mike | John |
| 5 | Mike | Charles |
+------------+---------------+-----------------+
How do i avoid that 2 times JOIN?
I'm using MS-SQL , but open to all SQL query for my own learning curious
Your current design/approach is acceptable, I think, and the need for two joins is a function of there being two user ID columns. Each of the two columns requires a separate join.
For fun, here is a table design which you may consider if you really want to have to perform only one join:
+------------+-----------+-------------+
| product_id | user_id | type |
+------------+-----------+-------------+
| 1 | 1 | created |
| 2 | 1 | created |
| 3 | 2 | created |
| 4 | 2 | created |
| 5 | 2 | created |
| 1 | 3 | modified |
| 2 | 3 | modified |
| 3 | 3 | modified |
| 4 | 1 | modified |
| 5 | 3 | modified |
+------------+-----------+-------------+
Now, you can get away with a just a single join followed by an aggregation:
SELECT
p.product_id,
MAX(CASE WHEN t.type = 'created' THEN u.Name END) AS CreateByName,
MAX(CASE WHEN t.type = 'modified' THEN u.Name END) AS ModifiedByName
FROM Product p
INNER JOIN user u
ON p.user_id = u.Id
GROUP BY
p.product_id;
Note that I don't recommend this approach at all. It is much cleaner to use your current approach and use two joins. Joins can fairly easily be optimized using one or more indices. The above aggregation approach would probably not perform as well as what you already have.
If you use natural keys instead of surrogates, you won't need to join at all.
I don't know how you tell your products apart in the real world, but for the example I will assume you have a UPC
CREATE TABLE User
(Name VARCHAR(20) PRIMARY KEY);
CREATE TABLE Product
(UPC CHAR(12) PRIMARY KEY,
CreatedBy VARCHAR(20) REFERENCES User(Name),
ModifiedBy VARCHAR(20) REFERENCES User(Name)
);
Now your query is a simple select, and you also enforce uniqueness of your user names as a bonus, and don't need additional indexes.
Try it...
HTH
Join is the best Approach, but if looking for alternate approach you can use Inline Query.
SELECT P.PRODUCT_ID,
(SELECT [NAME] FROM #USER WHERE ID = CREATED_BY) AS CREATED_BY,
(SELECT [NAME] FROM #USER WHERE ID = MODIFIED_BY) AS MODIFIED_BY
FROM #PRODUCT P
DEMO

In a while loop select only rows with different values of a column

I've got the following table:
ID User Data
1 isma A
123 john B
456 lucy A
789 isma A
111 luke A
And I want to select all those users whose values are only A but I don't want isma to appear twice, I mean select only unique users and please don't advise me to set a UNIQUE index on users because I can't. I'd be very grateful with any answer :)
This is my SQL: SELECT * FROM table WHERE data = 'A' but of course it outputs the user isma twice.
Use DISTINCT
SELECT DISTINCT User FROM table WHERE data = 'A';
Output
| User |
|------|
| isma |
| lucy |
| luke |
If you also want the count of users with same name and with Data = 'A' you can use Group By
SELECT User,
COUNT(*) AS 'User Count'
FROM table
WHERE Data = 'A'
GROUP BY User;
Output
| User | User Count |
|------|------------|
| isma | 2 |
| lucy | 1 |
| luke | 1 |

SQL query using GROUP_CONCAT() function

I have two tables:
1.Activity-- which stores all the activities from a user
2.User-- which stores all the registered users
I want to fetch all the posts and the likes to all posts in one query. A row is a post or like is decided by the value of type column.
Table Name - Activity
| actId | parentId | type | postedby |
---------------------------------------------------
| 100 | NULL | post | 100 |
| 200 | 100 | like | 200 |
| 300 | 100 | like | 300 |
| 400 | 100 | like | 400 |
| 500 | NULL | post | 100 |
| 600 | 500 | like | 600 |
Table Name - User
| userId | name |
-------------------
| 100 | Amit |
| 200 | Alok |
| 300 | Arjun |
| 400 | Arpeet |
| 600 | Amaan |
The output should be
| actId | name | LikedBy |
------------------------------------------
| 100 | Amit | Alok, Arjun, Arpeet|
| 500 | Amit | Amaan |
NOTE - I don't want this to be achieved using FOR XML PATH since it is not supported in SQLite which I am working on.
My query attempt was
SELECT a.id, u.name,
(select group_concat(u.name) from activity a, user u where a.id = u.id and a.type = 'like'
group by a.parent) as likedby
FROM activity a, user u
WHERE a.id = u.id and a.type = 'post'
The result I got was
| Id | name | LikedBy |
---------------------------------------
| 100 | Amit | Alok, Arjun, Arpeet|
You can see that the other row was missing from result.
Try this:
select t.id4id Id, n1.Name Name, group_concat(n2.name) Groups
from (select t1.actid id4id, t1.postedby id4name, t2.postedby id4groups
from Activity t1 join Activity t2 on t1.actid = t2.parentid) t join "user" n1 on t.id4name = n1.userid join "User" n2 on t.id4groups = n2.userid
group by id4id
Notes: 1. I assume that a post will always have a null value in parent
You do not need a subquery for this. You simply need two joins in order to get the values for the original name and the liked name:
select a.parentid, u.name, group_concat(ul.name separator ', ') as likedby
from activity a join
user ul
on a.postedby = ul.userid join
user u
on a.parentid = u.userid
where a.type = 'like'
group by a.parentid, u.name;

Remove dulicate rows using SQL

I want to know if there is a way to remove duplicate values from a table. The key 'distinct' will fetch us the unique rows however if one value differs in a column, it wont. so just wanted to know if this can be achieved by any means. Hope the below example will help.
For example : In the below table there are two entries for Emp_ID 1234 with two different priorities. my output should consider the higher priority row alone. Is it possible?
My table
+---------+------+--------+-------+
| Employee_ID| priority | gender |
+------------+-----------+--------+
| 1234 | 1 | F |
| 1234 | 10 | F |
| 5678 | 2 | M |
| 5678 | 25 | M |
| 9101 | 45 | F |
+------------+-----------+--------+
Output
+---------+------+--------+-------+
| Employee_ID| priority | gender |
+------------+-----------+--------+
| 1234 | 1 | F |
| 5678 | 2 | M |
| 9101 | 45 | F |
+------------+-----------+--------+
DELETE
FROM Table t
WHERE EXISTS ( SELECT Employee_ID FROM Table WHERE Employee_ID = t.Employee_ID AND priority < t.Priority)
That is if you really want to remove them from the table. The Exists part can also be used in a select query to leave the values in the Original table.
SELECT *
FROM Table t
WHERE NOT EXISTS (SELECT Employee_ID FROM Table WHERE Employee_ID = t.Employee_ID AND priority > t.Priority)
select Employee_ID,max(priority) as priority,gender
from table
group by Employee_ID,gender