How to get rid of duplicate by sql query - duplicates

I have a database table which stores email address data, date of join and a column newsletter (yes/no). However, there are lots of duplicate email addresses with different dates and values in the newsletter column. I need to write sql query that would exclude those emails (records) with more recent dates and leave only the records with the oldest dates:
EMAIL DATEJOIN NEWSLETTER
zzzzzzzzzz_#hotmail.com 02/03/2015 0
zzzzzzzzzz_#hotmail.com 30/06/2015 1
vishythamack#hotmail.com 22/09/2012 1
vishysblue#gmail.com 19/09/2012 1
yann-o#hotmail.fr 07/07/2015 0
yannnsheng#hotmail.com 02/03/2015 0
yannnsheng#hotmail.com 22/09/2012 1
thilaxanschool#gmail.com 18/09/2013 1
What I need After Query
EMAIL DATEJOIN NEWSLETTER
zzzzzzzzzz_#hotmail.com 02/03/2015 0
vishythamack#hotmail.com 22/09/2012 1
vishysblue#gmail.com 19/09/2012 1
yann-o#hotmail.fr 07/07/2015 0
yannnsheng#hotmail.com 22/09/2012 1
thilaxanschool#gmail.com 18/09/2013 1
I tried to use the following:
SELECT [EMAIL]
,min([DATEJOIN]) as [DATEJOIN]
, [NEWSLETTER]
FROM [test].[dbo].[first]
group by [EMAIL], [NEWSLETTER]
But it doesn't work. I need to decide what to do with the Newsletter field. Any thoughts?

I would recommend just finding everything with duplicate values and deleting the old ones using a script of some sort.
SELECT EMAIL
FROM [test].[dbo].[first]
having count(*) > 1
If you don't want to do that you could do something like:
SELECT a.* from first a
inner join (select email, min(datejoin) as join from first group by email) b
b on a.email = b.email and a.datejoin = b.datejoin
which should work.

Related

Show records where a value exist in all instances of a field by group

I am trying to figure out a way to show all records in table where a specific field does not contain certain values - table layout is:
id
tenant_id
request_action
request_id
request_status
hash
Each request_id could have multiple actions so it could look like:
1 1 email 1234 1 ffffd9b00cf893297ab737243c2b921c
2 1 email 1234 0 ffffd9b00cf893297ab737243c2b921c
3 1 email 1234 0 ffffd9b00cf893297ab737243c2b921c
4 1 email 1235 1 a50ee458c9878190c24cdf218c4ac904
5 1 email 1235 1 a50ee458c9878190c24cdf218c4ac904
6 1 email 1235 1 a50ee458c9878190c24cdf218c4ac904
7 1 email 1236 1 58c2869bc4cc38acc03038c7bef14023
8 1 email 1236 2 58c2869bc4cc38acc03038c7bef14023
9 1 email 1236 2 58c2869bc4cc38acc03038c7bef14023
Request_id can either be 0 (pending), 1 (sent) or 2 (failed) - I want to find all hashes where all the request_status within that hash are set to 1.
In the above two examples a50ee458c9878190c24cdf218c4ac904 should return as a match as all the request_status are 1 but ffffd9b00cf893297ab737243c2b921c should not as, whilst it contains a 1, it also contains some 0's and 58c2869bc4cc38acc03038c7bef14023 should not as, again whilst it contains a 1, it also contains some 2's
I tried:
SELECT
*
from
table
where request_action='email' and request_status!=0 and request_status!=2
group by hash
However, this doesn't give me the result I need - how can I return the hashes only where request_status is set to 1 for all the instances of that hash?
Not sure why you would need a group by here. You'd want to do a group by if you were going to concat data using GROUP_CONCAT, or other aggregate functions (sum, max, etc)
Also, instead of doing multiple negative conditions in your where clause (request_status !=0 and request_status !=2), why not just get the status you want?
SELECT * FROM test WHERE request_action = 'email' AND request_status = 1
Update Based on Your Comment
If you don't want to return any hashes that have the status of 0, or 2. You can do this:
SELECT
*
FROM
test t
WHERE
request_action = 'email' AND request_status = 1
AND HASH NOT IN (SELECT HASH FROM test WHERE request_status IN (0, 2))
Just make sure you have an index on hash, otherwise this is going to be really slow.
Create table temp select hash from your_table where
request_status=1 group by hash
Alter table temp add index(hash)
Delete from temp where hash IN (select hash from temp
where request_status!=1 group by hash)
Select * from your_table where hash IN(select hash from
temp)

MariaDB - How to add(JOIN) one more column from another table with IF/ELSE

I've got two tables called ARTICLE and SAVE.
ARTICLE table has entire article data. And SAVE table has the relation between email and seq of ARTICLE.
ARTICLE
seq email title content
1 fm#x.y ya hah
2 ch#x.y ho hihi
3 ch#x.y yo hoho
SAVE
seq email article_seq
3 ch#x.y 1
So, if you save the 3rd article with your account(a#x.y), SAVE table will be changed like...
SAVE
seq email article_seq
3 ch#x.y 1
4 a#x.y 3
And I'd like to create(The result of SELECT) one more column into ARTICLE call is_saved. And I expect this result of SELECT:
When I log in as ch#x.y
RESULT
seq email title content is_saved
1 fm#x.y ya hah 1
2 ch#x.y ho hihi 0
3 ch#x.y yo hoho 0
When I log in as fm#x.y
RESULT
seq email title content is_saved
1 fm#x.y ya hah 0
2 ch#x.y ho hihi 0
3 ch#x.y yo hoho 0
So, I need to JOIN the two tables based on ARTICLE and I may need IF/ELSE condition. How can I do this?
First you select all the articles (by a user) and you make a left join on the article seq id. You need a left join to distinct between saved (row exists) and not saved (row does not exist).
SELECT
*,
IF(s.is_saved IS NULL, 1, 0) as 'is_saved'
FROM 'ARTICLE' a
LEFT JOIN 'SAVE' s
ON a.seq = s.article_seq
WHERE a.email = :email
It looks like you also have a redundancy as email exists in both tables.
You seems want EXISTS :
select *, (case when exists (select 1 from SAVE s where s.article_seq = a.seq)
then 1 else 0
end) as is_saved
from ARTICLE a;
A left join is a natural way to express this:
select a.*,
(s.seq is not null) as is_saved
from article a left join
save s
on a.seq = s.article_seq and
a.email = s.email;
This assumes that a seq/email combination can appear at most once in save.
I solved this problem with...
SELECT *,
(CASE WHEN EXISTS
(SELECT 1
FROM save s
WHERE a.seq = s.article_seq AND s.email=?)
THEN 1 ELSE 0 END)
AS is_saved
FROM article a;
? is the login user email. If you may know Node.js or Spring (server side). You may understand what I mean. You use ? for an unspecific parameter.
For instance, you don't know which person would log in currently. At this point, you need to use the question mark, so that the right data goes to the SQL.

MySQL query to gather incorrectly stored data

I have recently taken over a email campaign project and need to generate a report for the customer. However the data has been stored very strangely.
Basically the client wants a report of the subscribers first name and last name that have subscribed to a emailing list.
Example table data.
------------------------------------------------------------
id | owner_id | list_id | field_id | email_address | value
------------------------------------------------------------
1 10 1 137 me#example.com John
2 10 1 138 me#example.com Doe
So as you can see, John Doe has subscribed to mailing list 1, and field_id 137 is his first name and field_id 138 is his last name.
The client is looking for a export with the users first name and last name all is one field.
I tred the following sql query
SELECT value
FROM Table_A AS child
INNER JOIN Table_A AS parent
ON parent.email_address = child.email_address
WHERE child.owner_id = '10'
But unfortunately the query gives me the results in many rows but not appending the first name and last name into one field,
If anyone can provide some assistance that would be awesome.
Thanks.
SELECT
concat( parent.value,' ',child.value)name
FROM mytable AS child
left JOIN mytable AS parent
ON parent.email_address = child.email_address
WHERE child.owner_id = '10'
and parent.field_id=137 and child.field_id=138
Check at-http://sqlfiddle.com/#!9/199b4b/45
I think you have to use a variable to put in there everything you have to and then select the variable with the desired name of yours.
For example:
DECLARE #yourvariable VARCHAR(MAX)
SELECT #yourvariable = COALESCE(#yourvariable + " ") + value
FROM table_A
WHERE owner_id = 10
SELECT #yourvariable as FullName
Try that, it might help.
You can try this code(column name equals value in your original DB):
select a.name
from
table_a a inner join table_a b
on a.email_address = b.email_address and a.field_id <> b.field_id
where a.owner_id=10
order by a.field_id
Here is the example link:
http://sqlfiddle.com/#!9/5fbdf6/25/0
As per assumptions, first name has the field id 137 and last name has the field id 138.
You can try the following query to get the desired result.
SELECT CONCAT(SUBSTRING_INDEX(GROUP_CONCAT(`value`),",",1)," ",SUBSTRING_INDEX(GROUP_CONCAT(`value`),",",-1)) AS client_name
FROM Table_A
WHERE owner_id = 10
AND field_id IN (137, 138)
GROUP BY email_address;

Get the No of Pending, Accepted and Rejected Users from two tables

I have two tables namely register and expressinterest
Where register table contains (user related columns) some are -
i) matri_id (unique but not primary)
ii) mobile
iii) email
iv) last_login
and expressinterest table contains data related to the matches details where columns are namely
i) ei_sender
ii) ei_receiver
iii) ei_response
iv) ei_sent_date
I am comparing the matri_id of register table to ei_sender and ei_receiver of expressinterest table, where one user can send requests to another users and he can receive request from another users.
I have to get the count of Pending, Accepted and Rejected status of all the users present in the register table, but when I am running the query it's running very slow, It takes around 45-60 seconds to fetch only 5000 rows in which the data is not proper (a single ID is coming in 3 rows like Accepted in one row, Rejected in one row and Pending in one row), But I want all the counts to come in a single row like this
r.matri_id | r._email | r.mobile | pending_count | accepted_ count | rejected_count| r.last_login
Some queries which I had tried so far are
select r.matri_id, r.email, r.mobile, r.last_login, e.receiver_response, count(e.receiver_response), e.ei_sender, e.ei_receiver from register r, expressinterest e where r.matri_id = e.ei_sender or r.matri_id = e.ei_receiver GROUP BY e.receiver_response, r.matri_id ORDER BY r.last_login DESC
This is what I want but its taking 5-6 seconds to execute
select matri_id, email, mobile, last_login, (select count(ei_sender) from expressinterest where ei_receiver=matri_id and receiver_response = 'Pending') AS pending_count_mine,
(select count(ei_sender) from expressinterest where ei_sender=matri_id and receiver_response = 'Accepted') AS accepted_count,
(select count(ei_sender) from expressinterest where ei_sender=matri_id and receiver_response = 'Rejected') AS rejected_count FROM register ORDER BY last_login DESC
Thanks
You can replace the multiple correlated subqueries with a single subquery and a left join:
select r.matri_id,
r.email,
r.mobile,
r.last_login,
t.accepted_count,
t.rejected_count,
t.pending_count
from register r
left join (
select ei_sender,
sum(receiver_response = 'Accepted') as accepted_count,
sum(receiver_response = 'Rejected') as rejected_count,
sum(receiver_response = 'Pending') as pending_count
from expressinterest
where receiver_response in ('Rejected', 'Accepted', 'Pending')
group by ei_sender
) t on r.matri_id = t.ei_sender;

Ignore columns in MySQL query result with null values

I have a MySql table as,
Name Month Salary
=======================================
A Salary_Month_Sept 15000
A Salary_Month_Oct 0
B Salary_Month_Sept 12000
B Salary_Month_Oct 0
C Salary_Month_Sept 13000
C Salary_Month_Oct 0
and I am querying that table as
select Name,
max(IF(Month = 'Salary_Month_Sept', Salary, 0)) AS 'Salary_Month_Sept',
max(IF(Month = 'Salary_Month_Oct', Salary, 0)) AS 'Salary_Month_Oct'
from myTable
Which returns the query result as
Name Salary_Month_Sept Salary_Month_Oct
=============================================
A 15000 0
B 12000 0
C 17000 0
How can i ignore the column containing only zero or null values from the above query result.
Don't use *. Name columns you want to have. The query is not a crystal ball. It doesn't know in front if there will be data for the column. To do something like that you need 2 queries, assuming the salaries are only positive:
Select sum(salary_sept), sum(salary_oct), ... for the condition you need.
Create second select only for columns returning sum bigger than zero.
The SQL has no time machine, sorry. You have to do your work yourself.