I need to make something to merge some users in PGSQL but I think that pgsql don't own the MERGE property. I just want to know how to make two users to be matched like this :
id | name | username | mail
1 | toto | tata | toto.tata#gmail.com
2 | titi | tutu | titi.tutu#gmail.com
Here I want to chose which data I would like I want to say that I want to merge only username from 2 to 1 so the result would be :
id | name | username | mail
1 | toto | tutu | toto.tata#gmail.com
You just need to select all the columns for first id and the column you need with second id will be a subquery in select list. Please check below answer for selecting merged result.
Schema and insert statements:
create table users (id int , name varchar(50), username varchar(50), mail varchar(50));
insert into users values (1 , 'toto' , 'tata' , 'toto.tata#gmail.com');
insert into users values (2 , 'titi' , 'tutu' , 'titi.tutu#gmail.com');
Query:
select id,name,(select username from users where id=2) username,mail from users where id=1
Output:
id
name
username
mail
1
toto
tutu
toto.tata#gmail.com
db<fiddle here
To merge the rows within the table you can first update first row with data from second row then delete the second row. Try this:
Schema and insert statements:
create table users (id int , name varchar(50), username varchar(50), mail varchar(50));
insert into users values (1 , 'toto' , 'tata' , 'toto.tata#gmail.com');
insert into users values (2 , 'titi' , 'tutu' , 'titi.tutu#gmail.com');
Update query:
update users set username=(select username from users where id=2) where id=1;
delete from users where id=2;
Select query:
select * from users
id
name
username
mail
1
toto
tutu
toto.tata#gmail.com
db<fiddle here
You could use aggregation:
select min(id) as id,
max(name) filter (where id = 1) as name,
max(username) filter (where id = 2) as username,
max(mail) filter (where id = 1) as mail
from t
where id in (1, 2);
This assumes that you want to pull particular column values from particular ids.
Or you could use join:
select t1.id, t1.name, t2.username, t1.mail
from t t1 join
t t2
on t1.id = 1 and t2.id = 2;
If you actually want to change the data, use update and delete:
update t t1
set username = t2.username
from t t2
where t1.id = 1 and t2.id = 2;
delete from t
where t.id = 2;
Here is a db<>fiddle.
Related
i wanna select a row where in another row with same userid is Active . like :
mytable
userid
userfield
fieldstatus
1
Name
Tom
1
account
Active
2
name
Jerry
2
account
Failed
I want to select tom in name user field where its account is active . I'm writing in python
You can use a subquery with exists:
select t.fieldstatus from mytable t where t.userfield = "name" and exists (select 1 from mytable t1 where t1.userid = t.userid and t1.userfield = "account" and t1.fieldstatus = "Active")
Output
fieldstatus
Tom
You can check the same userid value using exists
select *
from mytable t
where exists (
select * from mytable t2
where t2.userid=t.userid
and t2.userfield='account'
and t2.fieldstatus='Active'
)
Trying to compare between two columns and check if there are no records that exist with the reversal between those two columns. Other Words looking for instances where 1-> 3 exists but 3->1 does not exist. If 1->2 and 2->1 exists we will still consider 1 to be part of the results.
Table = Betweens
start_id | end_id
1 | 2
2 | 1
1 | 3
1 would be added since it is a start to an end with no opposite present of 3,1. Though it did not get added until the 3rd entry since 1 and 2 had an opposite.
So, eventually it will just return names where the reversal does not exist.
I then want to join another table where the number from the previous problem has its name installed on it.
Table = Names
id | name
1 | Mars
2 | Earth
3 | Jupiter
So results will just be the names of those that don't have an opposite.
You can use a not exists condition:
select t1.start_id, t1.end_id
from the_table t1
where not exists (select *
from the_table t2
where t2.end_id = t1.start_id
and t2.start_id = t1.end_id);
I'm not sure about your data volume, so with your ask, below query will supply desired result for you in Sql Server.
create table TableBetweens
(start_id INT,
end_id INT
)
INSERT INTO TableBetweens VALUES(1,2)
INSERT INTO TableBetweens VALUES(2,1)
INSERT INTO TableBetweens VALUES(1,3)
create table TableNames
(id INT,
NAME VARCHAR(50)
)
INSERT INTO TableNames VALUES(1,'Mars')
INSERT INTO TableNames VALUES(2,'Earth')
INSERT INTO TableNames VALUES(3,'Jupiter')
SELECT *
FROM TableNames c
WHERE c.id IN (
SELECT nameid1.nameid
FROM (SELECT a.start_id, a.end_id
FROM TableBetweens a
LEFT JOIN TableBetweens b
ON CONCAT(a.start_id,a.end_id) = CONCAT(b.end_id,b.start_id)
WHERE b.end_id IS NULL
AND b.start_id IS NULL) filterData
UNPIVOT
(
nameid
FOR id IN (filterData.start_id,filterData.end_id)
) AS nameid1
)
I think this requirement is rarely encountered so I couldn't search for similar questions.
I have a table that needs to update the ID. For example ID 123 in table1 is actually supposed to be 456. I have a separate reference table built that stores the mapping (e.g. old 123 maps to new id 456).
I used the below query but apparently it returned error 38104, columns referenced in the ON clause cannot be updated.
MERGE INTO table1
USING ref_table ON (table1.ID = ref_table.ID_Old)
WHEN MATCHED THEN UPDATE SET table.ID = ref_table.ID_New;
Is there other way to achieve my purpose?
Thanks and much appreciated for your answer!
Use the ROWID pseudocolumn:
SQL Fiddle
Oracle 11g R2 Schema Setup:
CREATE TABLE TABLE1( ID ) AS
SELECT 1 FROM DUAL UNION ALL
SELECT 2 FROM DUAL UNION ALL
SELECT 3 FROM DUAL;
CREATE TABLE REF_TABLE( ID_OLD, ID_NEW ) AS
SELECT 1, 4 FROM DUAL UNION ALL
SELECT 2, 5 FROM DUAL;
MERGE INTO TABLE1 dst
USING ( SELECT t.ROWID AS rid,
r.id_new
FROM TABLE1 t
INNER JOIN REF_TABLE r
ON ( t.id = r.id_old ) ) src
ON ( dst.ROWID = src.RID )
WHEN MATCHED THEN
UPDATE SET id = src.id_new;
Query 1:
SELECT * FROM table1
Results:
| ID |
|----|
| 4 |
| 5 |
| 3 |
You can't update a column used in the ON clause in a MERGE. But if you don't need to make other changes that MERGE allows like WHEN NOT MATCHED or deleting, etc. you can just use a UPDATE to achieve this.
You mentioned this is an ID that needs an update. Here's an example using a scalar subquery. As it is an ID, this presumes UNIQUE ID_OLD values in REF_TABLE. I wasn't sure if Every row needs an update or only a sub-set, so set the update here to only update rows that have a value in REF_TABLE.
CREATE TABLE TABLE1(
ID NUMBER
);
CREATE TABLE REF_TABLE(
ID_OLD NUMBER,
ID_NEW NUMBER
);
INSERT INTO TABLE1 VALUES (1);
INSERT INTO TABLE1 VALUES (2);
INSERT INTO TABLE1 VALUES (100);
INSERT INTO REF_TABLE VALUES (1,10);
INSERT INTO REF_TABLE VALUES (2,20);
Initial State:
SELECT * FROM TABLE1;
ID
1
2
100
Then make the UPDATE
UPDATE TABLE1
SET TABLE1.ID = (SELECT REF_TABLE.ID_NEW
FROM REF_TABLE
WHERE REF_TABLE.ID_OLD = ID)
WHERE TABLE1.ID IN (SELECT REF_TABLE.ID_OLD
FROM REF_TABLE);
2 rows updated.
And check the change:
SELECT * FROM TABLE1;
ID
10
20
100
I have a table with 4 columns of user information. Each table has the following columns:
Username | Full_Name | Job_Name | Current_Job_Allowed
Table 1 includes all users and the Job_Name which they have permissions to view. This means that there are multiple lines of the same username in Table 1 with different Job_Name values.
Table 2 contains a list of all possible users.
Username |Full_Name
--------------+-----------------
amunoz |Andrew Munoz
csmith |Carl Smith
cwatkins |Cat Watkins
ggriffiths |Garmin Griffiths
jcarr |Jason Carr
jhothi |Jark Hothi
jphillips |Jim Phillips
lbradfield |Lisa Bradfield
ntaylor |Noria Taylor
rfelipe |Ralf Felipe
Query 1 contains all users specified by a query parameter which I specify, i.e. 'KML_20160531'.
I would like to now select a DISTINCT list of all users which have a different Job_Name from the parameter I specify for Job_Name. For example Table 1 contains:
Username|Full_Name |Job_Name |Current_Job_Allowed
--------+------------+------------+----------------------
amunoz |Andrew Munoz|KML_20160531|1
jcarr |Jason Carr |KML_20160531|1
rfelipe |Ralf Felipe |KML_20140531|1
amunoz |Andrew Munoz|KML_20160431|1
I would then like to return the below when I enter 20160531 for Job_Name. This will return all possible new users for the Job_Name value I entered.
Username |Full_Name
--------------+---------------
csmith |Carl Smith
cwatkins |Cat Watkins
ggriffiths |Garmin Griffiths
jhothi |Jark Hothi
jphillips |Jim Phillips
lbradfield |Lisa Bradfield
ntaylor |Noria Taylor
rfelipe |Ralf Felipe
This parameter query will show you which users have a Table 1 row with Job_Name matching the parameter value:
PARAMETERS which_job Text ( 255 );
SELECT t1.[Username], t1.Job_Name
FROM [Table 1] AS t1
WHERE t1.Job_Name=[which_job];
So you can use that as a subquery, left join Table 2 to the subquery, and select the rows where the "right side" is Null:
PARAMETERS which_job Text ( 255 );
SELECT t2.[Username]
FROM
[Table 2] AS t2
LEFT JOIN
(
SELECT t1.[Username]
FROM [Table 1] AS t1
WHERE t1.Job_Name=[which_job]
) AS sub
ON t2.[Username] = sub.[Username]
WHERE sub.[Username] Is Null;
Assuming that query returns the correct rows, add the other field you want to see to SELECT t2.[Username].
You should not need DISTINCT unless Table 2 allows duplicate Username values, or Table 1 allows more than one row with the same combination of Username and Job_Name.
You can use not in and distinct
select distinct a.username, a.fullname
from table1 as a
where a.username not in (select distinct username
from table2 where job_name ='my_value');
and for only the job
select distinct a.username, a.fullname
from table1 as a
where a.username not in (select username
from table2
group by username
having count(job_name) = 1
and job_name ='my_value' );
You don't actually need DISTINCT for this query at all:
select t.*
from table1 as t
where not exists (select 1
from table2 as t2
where t2.username = t.username and t2.job_name = "KML_20160531"
);
From your description of the problem, Current_Job_Allowed does not seem relevant.
This will be syntax for your problem
SELECT DISTINCT UserName
FROM Table1
WHERE UserName NOT IN (
SELECT UserName From Table2
WHERE job_name = ''
);
I am having trouble with a join in sql.
I have 3 tables.
1: Lists the user details
2: Lists the permissions the user group has
3: Lists the page that that group can access
Table1 users :
****************************************
username | group
****************************************
admin | administrator
Table2 groups :
*********************************************
user_group | create | view | system_admin
*********************************************
administrator | 1 | 0 | 1
Table3 urls:
*********************************************
create | view | system_admin
*********************************************
create.php | view.php | system.php
(apologies for my table drawing)
What I am doing via php , is grabbing the user_group they belong to.
I then need to check if they have access to the page they have just hit or redirect them back.
Can I accomplish this with the current table layout the way they are through a join?, Or shall I look to re-design these tables as they are not intuitive for this kind of thing.
I actually might redesign the tables to make them easier to query:
create table users
(
id int,
username varchar(10),
groupid int
);
insert into users values (1, 'admin', 1);
create table groups
(
groupid int,
groupname varchar(20)
);
insert into groups values (1, 'administrator');
create table permissions
(
permissionid int,
permissionname varchar(20)
);
insert into permissions values (1, 'create');
insert into permissions values (2, 'view');
insert into permissions values (3, 'system_admin');
create table urls
(
urlid int,
name varchar(10)
);
insert into urls values(1, 'create.php');
insert into urls values(2, 'view.php');
insert into urls values(3, 'system.php');
create table group_permission_urls
(
groupid int,
permissionid int,
urlid int
);
insert into group_permission_urls values(1, 1, 1);
insert into group_permission_urls values(1, 0, 2);
insert into group_permission_urls values(1, 3, 3);
Then your query would be similar to this:
select *
from users us
left join groups g
on us.groupid = g.groupid
left join group_permission_urls gpu
on us.groupid = gpu.groupid
left join permissions p
on gpu.permissionid = p.permissionid
left join urls u
on gpu.urlid = u.urlid
see SQL Fiddle with Demo
By comparing the $current_page with the results of an IN() subquery, you can do this in one query. If the page matches any listed in a column the user has permission for, this will return a row. It should not return any row if there is no match in an allowed column.
SELECT
groups.create,
groups.view,
groups.system_admin,
1 AS can_access
FROM
users
JOIN groups ON users.group = groups.user_group
WHERE
users.username = '$some_username'
AND (
/* Substitute the current page. Better, use a prepared statement placeholder if your API supports it */
(groups.create = 1 AND '$current_page' IN (SELECT DISTINCT create FROM urls))
OR
(groups.view = 1 AND '$current_page' IN (SELECT DISTINCT view FROM urls))
OR
(groups.system_admin = 1 AND '$current_page' IN (SELECT DISTINCT system_admin FROM urls))
)
This works by comparing the $current_page to the distinct set of possible values from each of your 3 columns. If it matches a column and also the user's group has permission on that type, a row is returned.
select case when count(1) > 0 then 'come in' else 'go away' end
from users, groups, urls
where
users.username = '$username' and
users.user_group = groups.user_group and
((urls.create = '$url' and groups.create = 1) or
(urls.view = '$url' and groups.view = 1) or
(urls.system_admin = '$url' and groups.system_admin = 1))