I'm guessing this is too local but I can't figure out a way to make it more general (which might be why I'm not able to find my answer on Google).
We have an application that tracks contacts for our business. These contacts (Contact table) are either contacted through the phone (Contact_Phone table) or through email (Contact_Email). If the user is contacted through the phone an agent keeps track of the total number of seconds (Contact_Phone.totalSeconds). Through a piece of business logic that I have no control over email contacts are treated as one second. A user might be contact through just email, just phone, or both.
I'm trying to generate a report on how long we've spent contacting each user but I can't get the results I expect.
Tables:
CREATE TABLE IF NOT EXISTS `Contact` (
`id` INT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(45) NULL ,
PRIMARY KEY (`id`) )
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `Contact_Email` (
`id` INT NOT NULL AUTO_INCREMENT ,
`ContactId` INT NULL ,
PRIMARY KEY (`id`) ,
INDEX `contact_email_contact_idx` (`ContactId` ASC) ,
CONSTRAINT `contact_email_contact`
FOREIGN KEY (`ContactId` )
REFERENCES `Contact` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `Contact_Phone` (
`id` INT NOT NULL AUTO_INCREMENT ,
`totalSeconds` INT NULL ,
`ContactId` INT NULL ,
PRIMARY KEY (`id`) ,
INDEX `Contact_Phone_contact_idx` (`ContactId` ASC) ,
CONSTRAINT `Contact_Phone_contact`
FOREIGN KEY (`ContactId` )
REFERENCES `Contact` (`id` )
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
Test Data:
insert into Contact (id, name) values (1, 'Scott');
insert into Contact (id, name) values (2, 'Joe');
insert into Contact_Phone (totalSeconds, ContactId) values (10, 2);
insert into Contact_Phone (totalSeconds, ContactId) values (100, 2);
insert into Contact_Email (ContactId) values (1);
insert into Contact_Email (ContactId) values (1);
insert into Contact_Email (ContactId) values (2);
Query:
select
name,
(select sum(totalSeconds) from Contact_Phone where Contact_Phone.ContactId = Contact.id)
+
(select count(*) from Contact_Email where Contact_Email.ContactId = Contact.id)
from Contact;
Expected Results:
Joe 111
Scott 2
Actual Results:
Joe 111
Scott null
Thanks
How about using summaries and LEFT JOIN operations, like so?
SELECT Contact.name,
COALESCE(p.seconds,0) + COALESCE(e.seconds,0) seconds
FROM Contact.Name
LEFT JOIN (
SELECT ContactID AS id,
SUM(totalSeconds) AS seconds
FROM ContactPhone
GROUP BY ContactID
) p ON Contact.id = p.id
LEFT JOIN (
SELECT ContactID AS id,
COUNT(*) AS seconds
FROM ContactEmail
GROUP BY ContactID
) e ON Contact.id = e.id
The LEFT JOIN operations will preserve your result rows where one or the other of your "seconds" computations is NULL. And, the COALESCE operations will prevent your query from attempting arithmetic on NULL values, which yields NULL.
Related
MySQL Version 8.0 Schema SQL
CREATE TABLE IF NOT EXISTS `servers` (
`id` INT NOT NULL,
`name` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `companies` (
`id` INT NOT NULL,
`name` VARCHAR(45) NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `print` (
`id` INT NOT NULL,
`page` INT NOT NULL,
`copy` INT NOT NULL,
`date` DATE NOT NULL,
`server` INT NOT NULL,
PRIMARY KEY (`id`),
INDEX `fk_print_servers1_idx` (`server` ASC) VISIBLE,
CONSTRAINT `fk_print_servers1`
FOREIGN KEY (`server`)
REFERENCES `servers` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
CREATE TABLE IF NOT EXISTS `company_server` (
`server` INT NOT NULL,
`company` INT NOT NULL,
PRIMARY KEY (`server`, `company`),
INDEX `fk_servers_has_company_company1_idx` (`company` ASC) VISIBLE,
INDEX `fk_servers_has_company_servers_idx` (`server` ASC) VISIBLE,
CONSTRAINT `fk_servers_has_company_servers`
FOREIGN KEY (`server`)
REFERENCES `servers` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_servers_has_company_company1`
FOREIGN KEY (`company`)
REFERENCES `companies` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB;
insert into servers (id,name)
values
(1, 'server1'),
(2, 'server2'),
(3, 'server3'),
(4, 'server4');
insert into companies (id,name)
values
(1, 'company1'),
(2, 'company2'),
(3, 'company3');
insert into company_server (company,server)
values
(1,1),
(2,1),
(3,2),
(3,3);
insert into print (id,page,copy,date,server)
values
(1,2,3,'2020-1-11',1),
(2,1,6,'2020-1-12',3),
(3,4,5,'2020-1-13',4),
(4,5,3,'2020-1-15',2),
(5,3,4,'2020-1-15',4),
(6,1,2,'2020-1-16',3),
(7,2,2,'2020-1-16',4);
My query:
select
group_concat(c.name separator ',') as name_company,
ss.name,
sum_print as sum,
(sum_print/total) *100 as percentage
from companies c
inner join company_server cs on c.id = cs.company
right join servers ss on ss.id = cs.server
left join (
select
server,
sum(page*copy) as sum_print
from print
where date between CAST('2020-1-12' AS DATE) AND CAST('2020-1-15' AS DATE)
group by server
) tmp on tmp.server = ss.id
cross join (
select sum(page*copy) as total
from print
where date between CAST('2020-1-12' AS DATE) AND CAST('2020-1-15' AS DATE)
) tmp2
group by ss.id;
Mysql error output
Query Error: Error: ER_WRONG_FIELD_WITH_GROUP: Expression #4 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'tmp2.total' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
What I need:
That someone can point me, in the query above, which adjustment is missing so that the error is not thrown
DB Feedle
What I dont want:
Turn off ONLY_FULL_GROUP_BY
Extra notes:
The query works fine if ONLY_FULL_GROUP_BY is turned off
No embarrassment, I don't have good query fluency. I've already tried to read some stackoverflows answers about the same problem, but I ended up not understanding due to my limitation.
I think that by being pointed out where the problem is, maybe I can better understand what the other topics were pointing out.
My question in a SQL Fiddle.
How can I join all elements in table A with all elements in table B via a many-to-many mapping table, even if no relationship exists? My LEFT JOIN solution isn't giving the results I expect.
Details:
Given these tables:
CREATE TABLE `user` (
id INT PRIMARY KEY NOT NULL,
email VARCHAR(100) NOT NULL
);
CREATE TABLE `event` (
id INT NOT NULL,
start_time DATETIME NOT NULL,
PRIMARY KEY (id)
);
CREATE TABLE `event_response` (
id INT PRIMARY KEY NOT NULL,
user_id INT NOT NULL,
event_id INT NOT NULL,
response VARCHAR(5) NOT NULL,
FOREIGN KEY (user_id)
REFERENCES `user`(id)
ON DELETE CASCADE,
FOREIGN KEY (event_id)
REFERENCES `event`(id)
ON DELETE CASCADE
);
And this seed data:
-- create some users
INSERT INTO `user`(`id`, email)
VALUES
(1, 'abc1#gmail.com'),
(2, 'abc2#gmail.com'),
(3, 'abc3#gmail.com');
-- create two events
INSERT INTO `event`(`id`, start_time)
VALUES
(1, '2020-09-01'),
(2, '2020-10-01');
-- Only 3 users have responded to the events
INSERT INTO `event_response`(`id`, user_id, event_id, response)
VALUES
(1, 1, 1, 'yes'),
(2, 2, 1, 'no'),
(3, 3, 2, 'yes');
I need a report like this:
start_time, email, response
"2020-09-01", abc1#gmail.com, yes
"2020-09-01", abc2#gmail.com, no
"2020-09-01", abc3#gmail.com, <NO RESPONSE>
"2020-10-01", abc1#gmail.com, <NO RESPONSE>
"2020-10-01", abc2#gmail.com, <NO RESPONSE>
"2020-10-01", abc3#gmail.com, yes
The query I have tried (but doesn't give satisfactory results):
SELECT
e.start_time,
u.email,
COALESCE(er.response, '<NO RESPONSE>') AS response
FROM `user` AS u
LEFT JOIN event_response AS er ON u.id = er.user_id
LEFT JOIN `event` AS e ON er.event_id = e.id
ORDER BY e.start_time ASC;
Use a cross join to generate the rows and left join to bring in the values:
select e.*, u.*, er.response
from event e cross join
user u left join
event_response er
on er.user_id = u.id and er.event_id = e.id;
I have 2 tables, items and members :
CREATE TABLE IF NOT EXISTS `items` (
`id` int(5) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`member` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `members` (
`id` int(5) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
What if, for example I have a record inside items, such as
INSERT INTO `test`.`items` (
`id` ,
`name` ,
`member`
)
VALUES (
NULL , 'xxxx', '1, 2, 3'
);
in members :
INSERT INTO `members` (`id`, `name`) VALUES
(1, 'asdf'),
(2, 'qwert'),
(3, 'uiop'),
(4, 'jkl;');
and I'd like to display items.member data with members.name, something like 1#asdf, 2#qwert, 3#uiop??
I've tried the following query,
SELECT items.id, items.name, GROUP_CONCAT(CONCAT_WS('#', members.id, members.name) ) as member
FROM `items`
LEFT JOIN members AS members on (members.id = items.member)
WHERE items.id = 1
But the result is not like I expected. Is there any other way to display the data via one call query? Because I'm using PHP, right now, i'm explode items.member and loop it one by one, to display the members.name.
You could look into using FIND_IN_SET() in your join criteria:
FROM items JOIN members ON FIND_IN_SET(members.id, items.member)
However, note from the definition of FIND_IN_SET():
A string list is a string composed of substrings separated by “,” characters.
Therefore the items.member column should not contain any spaces (I suppose you could use FIND_IN_SET(members.id, REPLACE(items.member, ' ', '')) - but this is going to be extremely costly as your database grows).
Really, you should normalise your schema:
CREATE TABLE memberItems (
item_id INT(5) NOT NULL,
member_id INT(5) NOT NULL,
FOREIGN KEY item_id REFERENCES items (id),
FOREIGN KEY member_id REFERENCES members (id)
);
INSERT INTO memberItems
(item_id, member_id)
SELECT items.id, members.id
FROM items
JOIN members ON FIND_IN_SET(members.id, REPLACE(items.member,' ',''))
;
ALTER TABLE items DROP member;
This is both index-friendly (and therefore can be queried very efficiently) and has the database enforce referential integrity.
Then you can do:
FROM items JOIN memberItems ON memberItems.item_id = items.id
JOIN members ON members.id = memberItems.member_id
Note also that it's generally unwise to use GROUP_CONCAT() to combine separate records into a string in this fashion: your application should instead be prepared to loop over the resultset to fetch each member.
Please take a look at this sample:
SQLFIDDLE
Your query seems to work for what you have mentioned in the question... :)
SELECT I.ID, I.ITEM,
GROUP_CONCAT(CONCAT("#",M.ID,
M.NAME, " ")) AS MEMB
FROM ITEMS AS I
LEFT JOIN MEMBERS AS M
ON M.ID = I.MID
WHERE i.id = 1
;
EDITTED ANSWER
This query will not work for you¬ as your schema doesn't seem to have any integrity... or proper references. Plus your memeber IDs are delimtted by a comma, which has been neglected in this answer.
I have two tables, locations and location groups
CREATE TABLE locations (
location_id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(63) UNIQUE NOT NULL
);
INSERT INTO locations (name)
VALUES
('london'),
('bristol'),
('exeter');
CREATE TABLE location_groups (
location_group_id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
location_ids VARCHAR(255) NOT NULL,
user_ids VARCHAR(255) NOT NULL,
name VARCHAR(63) NOT NULL,
);
INSERT INTO location_groups (location_ids, user_ids, name)
VALUES
('1', '1,2,4', 'south east'),
('2,3', '2', 'south west');
What I am trying to do is return all location_ids for all of the location_groups where the given user_id exists. I'm using CSV to store the location_ids and user_ids in the location_groups table. I know this isn't normalised, but this is how the database is and it's out of my control.
My current query is:
SELECT location_id
FROM locations
WHERE FIND_IN_SET(location_id,
(SELECT location_ids
FROM location_groups
WHERE FIND_IN_SET(2,location_groups.user_ids)) )
Now this works fine if the user_id = 1 for example (as only 1 location_group row is returned), but if i search for user_id = 2, i get an error saying the sub query returns more than 1 row, which is expected as user 2 is in 2 location_groups. I understand why the error is being thrown, i'm trying to work out how to solve it.
To clarify when searching for user_id 1 in location_groups.user_ids the location_id 1 should be returned. When searching for user_id 2 the location_ids 1,2,3 should be returned.
I know this is a complicated query so if anything isn't clear just let me know. Any help would be appreciated! Thank you.
You could use GROUP_CONCAT to combine the location_ids in the subquery.
SELECT location_id
FROM locations
WHERE FIND_IN_SET(location_id,
(SELECT GROUP_CONCAT(location_ids)
FROM location_groups
WHERE FIND_IN_SET(2,location_groups.user_ids)) )
Alternatively, use the problems with writing the query as an example of why normalization is good. Heck, even if you do use this query, it will run more slowly than a query on properly normalized tables; you could use that to show why the tables should be restructured.
For reference (and for other readers), here's what a normalized schema would look like (some additional alterations to the base tables are included).
The compound fields in the location_groups table could simply be separated into additional rows to achieve 1NF, but this wouldn't be in 2NF, as the name column would be dependent on only the location part of the (location, user) candidate key. (Another way of thinking of this is the name is an attribute of the regions, not the relations between regions/groups, locations and users.)
Instead, these columns will be split off into two additional tables for 1NF: one to connect locations and regions, and one to connect users and regions. It may be that the latter should be a relation between users and locations (rather than regions), but that's not the case with the current schema (which could be another problem of the current, non-normalized schema). The region-location relation is one-to-many (since each location is in one region). From the sample data, we see the region-user relation is many-many. The location_groups table then becomes the region table.
-- normalized from `location_groups`
CREATE TABLE regions (
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(63) UNIQUE NOT NULL
);
-- slightly altered from original
CREATE TABLE locations (
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(63) UNIQUE NOT NULL
);
-- missing from original sample
CREATE TABLE users (
`id` INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
`name` VARCHAR(63) UNIQUE NOT NULL
);
-- normalized from `location_groups`
CREATE TABLE location_regions (
`region` INT UNSIGNED,
`location` INT UNSIGNED UNIQUE NOT NULL,
PRIMARY KEY (`region`, `location`),
FOREIGN KEY (`region`)
REFERENCES regions (id)
ON DELETE restrict ON UPDATE cascade,
FOREIGN KEY (`location`)
REFERENCES locations (id)
ON DELETE cascade ON UPDATE cascade
);
-- normalized from `location_groups`
CREATE TABLE user_regions (
`region` INT UNSIGNED NOT NULL,
`user` INT UNSIGNED NOT NULL,
PRIMARY KEY (`region`, `user`),
FOREIGN KEY (`region`)
REFERENCES regions (id)
ON DELETE restrict ON UPDATE cascade,
FOREIGN KEY (`user`)
REFERENCES users (id)
ON DELETE cascade ON UPDATE cascade
);
Sample data:
INSERT INTO regions
VALUES
('South East'),
('South West'),
('North East'),
('North West');
INSERT INTO locations (`name`)
VALUES
('London'),
('Bristol'),
('Exeter'),
('Hull');
INSERT INTO users (`name`)
VALUES
('Alice'),
('Bob'),
('Carol'),
('Dave'),
('Eve');
------ Location-Region relation ------
-- temporary table used to map natural keys to surrogate keys
CREATE TEMPORARY TABLE loc_rgns (
`location` VARCHAR(63) UNIQUE NOT NULL
`region` VARCHAR(63) NOT NULL,
);
-- Hull added to demonstrate correctness of desired query
INSERT INTO loc_rgns (region, location)
VALUES
('South East', 'London'),
('South West', 'Bristol'),
('South West', 'Exeter'),
('North East', 'Hull');
-- map natural keys to surrogate keys for final relationship
INSERT INTO location_regions (`location`, `region`)
SELECT loc.id, rgn.id
FROM locations AS loc
JOIN loc_rgns AS lr ON loc.name = lr.location
JOIN regions AS rgn ON rgn.name = lr.region;
------ User-Region relation ------
-- temporary table used to map natural keys to surrogate keys
CREATE TEMPORARY TABLE usr_rgns (
`user` INT UNSIGNED NOT NULL,
`region` VARCHAR(63) NOT NULL,
UNIQUE (`user`, `region`)
);
-- user 3 added in order to demonstrate correctness of desired query
INSERT INTO usr_rgns (`user`, `region`)
VALUES
(1, 'South East'),
(2, 'South East'),
(2, 'South West'),
(3, 'North West'),
(4, 'South East');
-- map natural keys to surrogate keys for final relationship
INSERT INTO user_regions (`user`, `region`)
SELECT user, rgn.id
FROM usr_rgns AS ur
JOIN regions AS rgn ON rgn.name = ur.region;
Now, the desired query for the normalized schema:
SELECT DISTINCT loc.id
FROM locations AS loc
JOIN location_regions AS lr ON loc.id = lr.location
JOIN user_regions AS ur ON lr.region = ur.region
;
Result:
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
I need to create a new table in oracle with only the most current date for each record (step 1), and calculate days between (step 2).
Your suggestions are greatly appreciated:)))
Step 1: First I need to find the max (Mod_date) for each record from table USERS.
TABLE: USERS
Name................Mod_Date
Jason Martin....... 25-JUL-89
Al Mathews......... 21-MAR-89
James Smith........ 12-DEC-88
Robert Black....... 15-JAN-84
Jason Martin....... 25-JUL-99
Al Mathews......... 21-MAR-96
James Smith........ 12-DEC-98
Robert Black....... 15-JAN-94
*TABLE_DESIRED_RESULTS_step1
Name............... Max(Mod_Date)
Jason Martin....... 25-JUL-99
Al Mathews......... 21-MAR-96
James Smith........12-DEC-98
Robert Black.......15-JAN-94
Step 2: Calculate “Number of Days Between Regist_Date and Mod_Date” & add it to the table.
TABLE: REGISTRATION
Name................Regist_Date
Jason Martin.........20-JUL-99
Al Mathews...........23-MAR-96
Robert Black.........20-JAN-94
*TABLE_DESIRED_RESULTS_step2
Name...............Max(Mod_Date).....Number of Days Between Regist_Date and Mod_Date
Jason Martin...... 25-JUL-99..........5
Al Mathews........ 21-MAR-96.........-2
James Smith....... 12-DEC-98..........null
Robert Black...... 15-JAN-94..........-5
*Please note, this data is made up and I already have existing unions and joins to which I have to add this logic. Thanks and have a nice day!
here is my updated answer with a sample.
The important thing is that your date column have the DATE type.
Here is the tables and data following your specification.
CREATE TABLE USERS
(
ID_USER NUMBER(6) NOT NULL,
NAME VARCHAR2(64) NOT NULL,
MOD_DATE DATE NOT NULL,
CONSTRAINT PK_user PRIMARY KEY (ID_USER)
) ;
INSERT INTO USERS VALUES (1,'Jason Martin',TO_DATE('25-07-1989','DD-MM-YYYY'));
INSERT INTO USERS VALUES (2,'Al Mathews',TO_DATE('21-03-1989','DD-MM-YYYY'));
INSERT INTO USERS VALUES (3,'James Smith',TO_DATE('12-12-1988','DD-MM-YYYY'));
INSERT INTO USERS VALUES (4,'Robert Black',TO_DATE('15-01-1984','DD-MM-YYYY'));
INSERT INTO USERS VALUES (5,'Jason Martin',TO_DATE('25-07-1999','DD-MM-YYYY'));
INSERT INTO USERS VALUES (6,'Al Mathews',TO_DATE('21-03-1996','DD-MM-YYYY'));
INSERT INTO USERS VALUES (7,'James Smith',TO_DATE('12-12-1998','DD-MM-YYYY'));
INSERT INTO USERS VALUES (8,'Robert Black',TO_DATE('15-01-1994','DD-MM-YYYY'));
CREATE TABLE REGISTRATION
(
ID_REG NUMBER(6) NOT NULL,
NAME VARCHAR2(64) NOT NULL,
REGIST_DATE DATE NOT NULL,
CONSTRAINT PK_reg PRIMARY KEY (ID_REG)
) ;
INSERT INTO REGISTRATION VALUES (1,'Jason Martin',TO_DATE('20-07-1999','DD-MM-YYYY'));
INSERT INTO REGISTRATION VALUES (2,'Al Mathews',TO_DATE('23-03-1996','DD-MM-YYYY'));
INSERT INTO REGISTRATION VALUES (3,'Robert Black',TO_DATE('20-01-1994','DD-MM-YYYY'));
First step
CREATE TABLE TABLE_DESIRED_RESULTS_step1
AS (
SELECT
u.NAME
, max(u.MOD_DATE) as "maxi"
FROM USERS u
GROUP BY u.NAME);
second step
CREATE TABLE TABLE_DESIRED_RESULTS_step2
AS (
SELECT
t.NAME
,t."maxi"
, (t."maxi" - r.REGIST_DATE ) as "Nbdays bw RegD and Mod_D"
FROM TABLE_DESIRED_RESULTS_step1 t LEFT OUTER JOIN REGISTRATION r
ON t.NAME = r.NAME);
The trick here is that LEFT OUTER JOIN allows null value if there is no match with the join.
But there is a database design concern for me.
If you have 2 users with the exact same name , you will merge 2 persons in one.
Here a solution using IDs and doing the join on the IDs.
CREATE TABLE USERS
(
ID_USER NUMBER(6) NOT NULL,
NAME VARCHAR2(64) NOT NULL,
CONSTRAINT PK_user PRIMARY KEY (ID_USER)
) ;
CREATE TABLE MOD_USERS
(
ID_MOD NUMBER(6) NOT NULL,
ID_USER NUMBER(6) NOT NULL,
CONSTRAINT PK_usermod PRIMARY KEY (ID_MOD)
) ;
ALTER TABLE MOD_USERS ADD (
CONSTRAINT FK_user_mod
FOREIGN KEY (ID_USER)
REFERENCES USERS (ID_USER));
CREATE TABLE REGISTRATION
(
ID_REG NUMBER(6) NOT NULL,
ID_USER VARCHAR2(64) NOT NULL,
REGIST_DATE DATE NOT NULL,
CONSTRAINT PK_reg PRIMARY KEY (ID_REG)
) ;
ALTER TABLE REGISTRATION ADD (
CONSTRAINT FK_user_reg
FOREIGN KEY (ID_USER)
REFERENCES USERS (ID_USER))
;
First step
CREATE TABLE TABLE_DESIRED_RESULTS_step1
AS (
SELECT
m.ID_USER , u.NAME
, max(u.MOD_DATE) as "maxi"
FROM USERS u INNER JOIN MOD_USERS m
ON u.ID_USER = m.ID_USER
GROUP BY m.ID_USER , u.NAME);
second step
CREATE TABLE TABLE_DESIRED_RESULTS_step2
AS (
SELECT
t.ID_USER , t.NAME
,t."maxi"
, (t."maxi" - r.REGIST_DATE ) as "Nbdays bw RegD and Mod_D"
FROM TABLE_DESIRED_RESULTS_step1 t LEFT OUTER JOIN REGISTRATION r
ON t.ID_USER = r.ID_USER);