Get users who don't have sent email MySQL - mysql

My DB has the following tables,
User (id, name)
EmailTemplate (id, subject, template)
EmailTrack (id, user_id, email_template_id)
I want to get the users who don't have sent specific email_template yet by the SQL query.

You could use the not exists operator:
SELECT *
FROM user u
WHERE NOT EXISTS (SELECT *
FROM emailtemplate temp
JOIN emailtrack track ON temp.id = track.email_template_id
WHERE template = 'some_specific_template' AND
track.user_id = u.id)

Related

MySQL query to get all friends of a user including the last sent message between them

I have 3 tables:
os_users (username, user_id),
os_friends (user_id, target_id, lastaction, time),
os_messages (user_id, target_id, message, time).
I now want to get all the "friends" of a user including the last 1 message that was written between both of them.
This query is working fine to get all friends and their usernames, ordered by lastaction between them (24 is for test purposes, its my user_id):
SELECT os_friends.*, os_users.username, os_users.user_id AS friend_id
FROM os_friends
LEFT JOIN os_users ON os_friends.user_id = os_users.user_id OR os_friends.target_id = os_users.user_id
WHERE os_users.user_id != 24 AND (os_friends.user_id = 24 OR os_friends.target_id = 24)
ORDER BY os_friends.lastaction DESC
I would like to get the last message (don't matter who of the 2 people sent it) of that "friendship" too in the results, best would be "AS lastmessage".
Hope you can help me out!
Suppose that (user_id, target_id, time) is unique in os_messages table
Select * from os_users osu
left join os_friends osf on osu.user_id = osf.user_id
left join os_messages osm on osm.user_id = osf.user_id and osm.target_id = osf.target_id
where not exists (
Select * from os_messages osm1 where osm1.user_id = osm.user_id and osm1.target_id = osm.target_id and osm1.time > osm.time
)

UNION query functionality and the query structure

What I'm trying to achieve is to insert values into a table if that value does not exist in 2 extra tables.
INSERT INTO visitor(
visitor_username,
email,
PASSWORD
)
SELECT * FROM
(
SELECT
'admin2000',
'adminemail#mail.com',
'123456'
) AS tmp
WHERE NOT EXISTS
(
SELECT
admin.admin_username,
admin.email
FROM
admin AS admin
WHERE
admin.admin_username = 'admin2000' AND admin.email =
'adminemail#mail.com'
UNION
SELECT
staff.staff_username,
staff.email
FROM
staff AS staff
WHERE
staff.staff_username = 'admin2000' AND staff.email =
'adminemail#mail.com'
)
LIMIT 1
In the WHERE NOT EXIST part when I only ask for *_username (example: admin_username or staff_username) it works well, but when I need to verify if the email exists too it does not work as intended.
Am I using WHERE NOT EXIST properly? if the username 'admin2000' and email 'adminemail#mail.com' exist on the table 'admin' and I'm trying to insert it into 'visitor' table it inserts it and it should not be doing that.
The problem is the AND in the subqueries. It searches for rows that have that username AND that email. So if you have an admin called admin2000, but with a different e-mail address, that admin won't be returned by the subquery, and so the new row will be inserted.
Use OR instead of AND, and the the problem will be solved.
You seem to want to be writing a query like this:
INSERT INTO visitor (visitor_username, email, PASSWORD)
SELECT t.*
FROM (SELECT 'admin2000' as visitor_username, 'adminemail#mail.com' as email, '123456' as PASSWORD
) t
WHERE NOT EXISTS (SELECT 1
FROM admin a
WHERE a.visitor_username = t.visitor_username AND a.email = t.email
)
UNION
SELECT s.staff_username, s.email, ? as password
FROM staff s
WHERE s.staff_username = 'admin2000' AND s.email =
'adminemail#mail.com';
Note that the second subquery is missing a password, so there is an error.
This seems more concisely written using a single query:
INSERT INTO visitor (visitor_username, email, PASSWORD)
SELECT t.*
FROM (SELECT 'admin2000' as visitor_username, 'adminemail#mail.com' as email, '123456' as PASSWORD
) t
WHERE NOT EXISTS (SELECT 1
FROM admin a
WHERE a.admin_username = t.visitor_username AND a.email = t.email
) AND
NOT EXISTS (SELECT 1
FROM staff s
WHERE s.staff_username = t.visitor_username AND s.email = t.email
);

how to count 2 table into another one in access 2013?

I have 2 system log table in access 2013, one is loged by email and another one is loged by userid.
log1
email datetime msg
log2
userid datetime msg
I want to count how many msg the user send by month and save into a table user_msg_count
yearmonth userid msg_count
SELECT format([log1].datetime,"yyyy/mm") AS yearmonth, log1.email, COUNT(log1.msg) AS msg_count INTO user_msg_count
FROM log1
GROUP BY FORMAT(log1.datetime,"yyyy/mm", log1.email;
then I get userid from users table
users
userid email
UPDATE user_msg_count, users SET user_msg_count.userid = users.userid
WHERE user_msg_count.email = users.email;
but I dont know how to plus the log2 into the user_msg_count table.
Is the email the sender (User) email or the receipient?
If User email:
LogUnion query:
SELECT Users.UserID, Format([DateSend],"yyyymm") AS YrMo, "L1" AS Source FROM Users INNER JOIN Log1 ON Users.emailAdd = Log1.email
UNION ALL SELECT UserID, Format([DateSend],"yyyymm"), "L2" FROM Log2;
TotalCount query:
SELECT LogUnion.UserID, LogUnion.YrMo, Count(*) AS CountMsg
FROM LogUnion
GROUP BY LogUnion.UserID, LogUnion.YrMo;
Nested all-in-one query:
SELECT LogUnion.UserID, LogUnion.YrMo, Count(*) AS CountOfSource
FROM (SELECT Users.UserID, Format([DateSend],"yyyymm") AS YrMo, "L1" AS Source FROM Users INNER JOIN Log1 ON Users.emailAdd = Log1.email
UNION ALL SELECT UserID, Format([DateSend],"yyyymm"), "L2" FROM Log2) AS LogUnion
GROUP BY LogUnion.UserID, LogUnion.YrMo;

MYSQL - SELECT AS alias to be used in subquery

I want to be able to use one of the items I am selecting further down in my sub query.
As you can see in this example I have set the "variable" in question as 100 but in reality this is going to be a dynamic number so I will need to be able to access it in the subquery.
INSERT INTO users_friends (userId, friendId)
SELECT 77, id as noob
FROM users WHERE email = 'a#g.com'
AND
NOT EXISTS (SELECT * FROM users_friends
WHERE userId = 77 and friendId = noob)
LIMIT 1
I'm not completely sure I understand your question, but NOT EXISTS works just like LEFT JOIN and IS NULL. So I think this will work:
SELECT 77, #noob
FROM users u
JOIN (SELECT #noob:= 100) r
LEFT JOIN users_friends uf on u.userid = uf.userid and uf.friendid = #noob
WHERE email = 'a#g.com'
AND uf.userid IS NULL
And here is the SQL Fiddle.
I think the safest approach is to define these in a subquery. I typically give this the alias of const:
INSERT INTO users_friends (userId, friendId)
SELECT const.userId, const.noob
FROM users cross join
(select 77 as userId, 100 as noob) const
WHERE email = 'a#g.com' AND
NOT EXISTS (SELECT *
FROM users_friends
WHERE userId = const.userId and friendId = const.noob
)
LIMIT 1
I am concerned about SGeddes's approach, because it relies on the correct evaluation of variables outside the scope of the query. This might work in this case, but I prefer a solution where the query does not rely on outside variables. By the way, this should also work in any database, and is not MySQL-specific.
EDIT
I would recommend changing your table structure.
CREATE TABLE users_friends(
userid int,
friendid int,
primary key (userid, friendid)
);
CREATE TABLE users (
userid int primary key,
email varchar(100),
name VARCHAR (100),
index (email,name)
);
INSERT INTO users VALUES (1, 'a#g.com', 'noob'), (2,'b#g.com', 'Joe');
INSERT INTO users_friends (userId, friendId)
VALUES (2, (SELECT userId
FROM users
WHERE email = 'a#g.com'
AND name = "noob"
AND NOT exists (SELECT * FROM users_friends as uf
JOIN users as u
ON u.userid = uf.userid
where uf.friendid = 2 AND name = "noob"
)
)
);
SQL FIDDLE DEMO
Try this:
<?php
function select_query ($userid,$friendname, $email){
$host = "host";
$user = "username";
$password = "password";
$database = "database name";
// open connection to databse
$link = mysqli_connect($host, $user, $password, $database);
IF (!$link){
echo ("Unable to connect to database!");
}
ELSE {
//Is someone registered at other conference from table registration
$query = " INSERT INTO users_friends (userId, friendId)
VALUES (".$userId.", (SELECT userId
FROM users
WHERE email = '".$email."'
AND name = '".$friendname."'
AND NOT exists (SELECT * FROM users_friends as uf
JOIN users as u
ON u.userid = uf.userid
where uf.friendid = ".$userId." AND name = '"$friendname"'
)
)
)";
$result = mysqli_query($link, $query);
return $query;
return $result;
}
mysqli_close($link);
}
echo select_query(1,noob,'a#g.com');
?>
Like I mentioned above I not sure what you mean. If you mean dynamic in the sense that you can change the value of the variable this might help. In your previous posts you used PHP. So, my guess is that your are using PHP.
INSERT INTO users_friends (userId, friendId)
SELECT 77, id
FROM users WHERE email = 'a#g.com'
AND
NOT EXISTS (SELECT * FROM users_friends
WHERE userId = 77 and friendId = (SELECT id
FROM users WHERE email = 'a#g.com'))
LIMIT 1

Substitute for MySQL's variables in PostgreSQL?

We often use quick one-off SQL files to insert or update data in an existing database. The SQL is usually written by a developer, tested on the development system, and then imported in the production DB with psql -U dbuser dbname < file.sql.
A (trivial) example might look like this:
INSERT INTO employees (
company_id,
name,
position,
created_by,
last_modified_by
) VALUES
(
(SELECT id FROM companies WHERE name = 'Acme Fellowship'),
'Frodo Baggins',
'Ring bearer',
(SELECT id FROM users WHERE login = 'admin'),
(SELECT id FROM users WHERE login = 'admin')
),
(
(SELECT id FROM companies WHERE name = 'Acme Fellowship'),
'Samwise Gamgee',
'Rope bearer',
(SELECT id FROM users WHERE login = 'admin'),
(SELECT id FROM users WHERE login = 'admin')
),
(
(SELECT id FROM companies WHERE name = 'Acme Fellowship'),
'Peregrin Took',
'Ent rider',
(SELECT id FROM users WHERE login = 'admin'),
(SELECT id FROM users WHERE login = 'admin')
);
While this works, there's a lot of repetitive code in the subqueries. It would be nice (more efficient and less error prone) to store the relevant values for companies.id and users.id in temporary variables. In this construed example, the performance difference is likely minimal, but in practice we do have more complex queries and updates, and there are often more than three updated/inserted records.
The same example written for MySQL looks like this:
SELECT #company_id := id FROM companies WHERE name = 'Acme Fellowship';
SELECT #admin_id := id FROM users WHERE login = 'admin';
INSERT INTO employees (
company_id,
name,
position,
created_by,
last_modified_by
) VALUES
(#company_id, 'Frodo Baggins', 'Ring bearer', #admin_id, #admin_id),
(#company_id, 'Samwise Gamgee', 'Rope bearer', #admin_id, #admin_id),
(#company_id, 'Peregrin Took', 'Ent rider', #admin_id, #admin_id);
Is there any way to achieve something similar in PostgreSQL?
What I've looked at:
psql's session variables (with \set): cannot be used to store query results
plpgsql: can only be used in a procedure (we're still running 8.4)
temporary tables: I can't see how to use them without creating ugly and convoluted statements
If there is no direct equivalent for Postgres, what do you think would be the least clumsy way to produce update files of this kind?
Use VALUES() in a SELECT, that should work:
INSERT INTO employees (
company_id,
name,
position,
created_by,
last_modified_by
)
SELECT
(SELECT id FROM companies WHERE name = 'Acme Fellowship'),
name,
position,
(SELECT id FROM users WHERE login = 'admin'),
(SELECT id FROM users WHERE login = 'admin')
FROM
(VALUES -- all your new content here
('Frodo Baggins', 'Ring bearer'),
('Samwise Gamgee', 'Rope bearer'),
('Peregrin Took', 'Ent rider')
) content(name, position); -- use some aliases to make it readable
Consider using CTEs or subqueries to query values once and inserted them many times.
This way, you can replace MySQL style variables with standard SQL.
INSERT INTO employees
(company_id, name, position, created_by, last_modified_by)
SELECT c.id , name, position, u.id , u.id
FROM (SELECT id FROM companies WHERE name = 'Acme Fellowship') c
,(SELECT id FROM users WHERE login = 'admin') u
,(VALUES
('Frodo Baggins', 'Ring bearer')
,('Samwise Gamgee', 'Rope bearer')
,('Peregrin Took', 'Ent rider')
) v(name, position)
Assuming that companies.name and users.login are, in fact, unique. Multiple hits would multiply the rows to be inserted.
Read about the INSERT command in the manual.
Here is my test setup with temporary tables in case anyone wants to have a quick look:
CREATE TEMP TABLE companies (id int, name text);
INSERT INTO companies VALUES (17, 'Acme Fellowship');
CREATE TEMP TABLE users (id int, login text);
INSERT INTO users VALUES (9, 'admin');
CREATE TEMP TABLE employees (
company_id int
,name text
,position text
,created_by int
,last_modified_by int);
This is an old question, but I found that using WITH statements made my life easier :)
WITH c AS (
SELECT company_id,
FROM companies
WHERE name = 'Acme Fellowship'
), u AS (
SELECT *
FROM users
WHERE login = 'admin'
), n AS (
SELECT *
FROM
(VALUES -- all your new content here
('Frodo Baggins', 'Ring bearer'),
('Samwise Gamgee', 'Rope bearer'),
('Peregrin Took', 'Ent rider')
) content(name, position)
)
INSERT INTO employees (
company_id,
name,
position,
created_by,
last_modified_by
)
SELECT c.company_id, n.name, n.position, u.id, u.id
FROM c, u, n