How to get only row without a specific value in a column - mysql

this is a huge problem i've to solve in sql but i don't know how.
This is my dataset:
customer; publisher; qty
This is a data sample:
CustA; PublX; 10
CustA; PublZ; 20
CustA; PublF; 30
CustB; PublX; 8
CustC; PublD; 9
CustD; PublX; 9
CustD; MyPub; 18
CustE; PublZ; 3
CustE; MyPub; 8
I need to do a Query that get ONLY Customer without "MyPubl" as publisher.
Obviously i can't do :
SELECT * from myTable where Publisher <>"MyPubl"
One solution can be that i create a subset table that aggregate customer in one row like this:
CustA; PublX PublZ PublF; 60
CustB; PublX; 8
etc...
Then with a INSTR i check if MyPub exists in second field ...
This solution my work.. so i ask you How can i do this in SQL (aggregate 'same' customers in one row) ?
Any others suggestion (maybe more elegant) ?
Thanks

You can use NOT IN with a sub query:
SELECT
customer,
publisher,
qty
FROM
books
WHERE
customer NOT IN (
SELECT
DISTINCT customer
FROM
books
WHERE
publisher = 'MyPub'
)
SQL Fiddle Demo
Which will output:
CUSTOMER | PUBLISHER | QTY
---------+-----------+-----
CustA | PublZ | 20
CustA | PublF | 30
CustB | PublX | 8
CustC | PublD | 9

Maybe this:
SELECT * FROM myTable
WHERE customer NOT IN (SELECT customer FROM myTable WHERE Publisher = "MyPubl")
Or if you just want the customers
SELECT DISTINCT customer FROM myTable

Or old skool...
SELECT DISTINCT x.customer
FROM my_table x
LEFT
JOIN my_table y
ON y.customer = x.customer
AND y.publisher = 'MyPub'
WHERE y.customer IS NULL;

Related

Get count of multiple table records with group by function

I have 2 tables : priority_list and priority_list_delete
I want to get the following data in a single row:
1) Sum of these 2 table records
2) Count of individual table records
3) Count of priority_list_delete table records category wise
This is what I have done so far:
SELECT
(SELECT COUNT(*) FROM priority_list)+(SELECT COUNT(*) from
priority_list_delete) as tot_count,
(SELECT COUNT(*) FROM priority_list) as prior_cnt,
(SELECT COUNT(*) FROM priority_list_delete) as prior_del_cnt
The above query returns the count of the tables but when I merge the below query with the above one, it throws an error:
(SELECT category, COUNT(*) FROM priority_list_delete group by category)
I guess, there is some syntax error which I am unable to sort it out and moreover I am not getting idea about how to get the count records category wise where category names will be the column name.
Example format:
tot_count| prior_cnt| prior_del_cnt| ST | OBC
---------|----------|--------------|------|------
920 | 893 | 27 | 64 | 100
Here ST and OBC are the categories.
Any help would be appreciated.
Thanks in advance.
I think your exact desired output might be tough to do, because the number of category columns is dynamic. But we can try reporting categories across rows:
SELECT category, cnt
FROM
(
SELECT category, COUNT(*) AS cnt, 0 AS pos
FROM priority_list_delete
GROUP BY category
UNION ALL
SELECT 'prior_cnt', COUNT(*), 1 FROM priority_list
UNION ALL
SELECT 'prior_del_cnt', COUNT(*), 2 FROM priority_list_delete
UNION ALL
SELECT 'tot_count', (SELECT COUNT(*) FROM priority_list) +
(SELECT COUNT(*) FROM priority_list_delete), 3
) t
ORDER BY pos, category;
This would give an output looking something like:
category | cnt
ST | 64
OBC | 100
prior_cnt | 893
prior_del_cnt | 27
tot_count | 920

SQL - select rows that have the same value in two columns

The solution to the topic is evading me.
I have a table looking like (beyond other fields that have nothing to do with my question):
NAME,CARDNUMBER,MEMBERTYPE
Now, I want a view that shows rows where the cardnumber AND membertype is identical. Both of these fields are integers. Name is VARCHAR. Name is not unique, and duplicate cardnumber, membertype should show for the same name, as well.
I.e. if the following was the table:
JOHN | 324 | 2
PETER | 642 | 1
MARK | 324 | 2
DIANNA | 753 | 2
SPIDERMAN | 642 | 1
JAMIE FOXX | 235 | 6
I would want:
JOHN | 324 | 2
MARK | 324 | 2
PETER | 642 | 1
SPIDERMAN | 642 | 1
this could just be sorted by cardnumber to make it useful to humans.
What's the most efficient way of doing this?
What's the most efficient way of doing this?
I believe a JOIN will be more efficient than EXISTS
SELECT t1.* FROM myTable t1
JOIN (
SELECT cardnumber, membertype
FROM myTable
GROUP BY cardnumber, membertype
HAVING COUNT(*) > 1
) t2 ON t1.cardnumber = t2.cardnumber AND t1.membertype = t2.membertype
Query plan: http://www.sqlfiddle.com/#!2/0abe3/1
You can use exists for this:
select *
from yourtable y
where exists (
select 1
from yourtable y2
where y.name <> y2.name
and y.cardnumber = y2.cardnumber
and y.membertype = y2.membertype)
SQL Fiddle Demo
Since you mentioned names can be duplicated, and that a duplicate name still means is a different person and should show up in the result set, we need to use a GROUP BY HAVING COUNT(*) > 1 in order to truly detect dupes. Then join this back to the main table to get your full result list.
Also since from your comments, it sounds like you are wrapping this into a view, you'll need to separate out the subquery.
CREATE VIEW DUP_CARDS
AS
SELECT CARDNUMBER, MEMBERTYPE
FROM mytable t2
GROUP BY CARDNUMBER, MEMBERTYPE
HAVING COUNT(*) > 1
CREATE VIEW DUP_ROWS
AS
SELECT t1.*
FROM mytable AS t1
INNER JOIN DUP_CARDS AS DUP
ON (T1.CARDNUMBER = DUP.CARDNUMBER AND T1.MEMBERTYPE = DUP.MEMBERTYPE )
SQL Fiddle Example
If you just need to know the valuepairs of the 3 fields that are not unique then you could simply do:
SELECT concat(NAME, "|", CARDNUMBER, "|", MEMBERTYPE) AS myIdentifier,
COUNT(*) AS count
FROM myTable
GROUP BY myIdentifier
HAVING count > 1
This will give you all the different pairs of NAME, CARDNUMBER and MEMBERTYPE that are used more than once with a count (how many times they are duplicated). This doesnt give you back the entries, you would have to do that in a second step.

MySQL: How to limit results to max value of another field?

In this scenario, I am trying to report on the operating_system_version for each distinct computer_id where the report_id for that computer_id is the greatest.
Currently, I am getting the below results:
operating_system_version | computer_id | report_id
10.8 | 1 | 10
10.9 | 1 | 20
10.9 | 2 | 11
10.8 | 2 | 21
The above is returned by this statement:
SELECT operating_systems.operating_system_version,
reports.computer_id,
reports.report_id
FROM operating_systems
INNER JOIN reports
ON operating_systems.report_id = reports.computer_id
Instead, would like return the most recent (highest report_id) operating_system_version for each distinct computer_id, for example:
operating_system_version | computer_id | report_id
10.9 | 1 | 20
10.8 | 2 | 21
I am brand new to SQL .. Appreciate any help.
You would need to add a group by statement and a having statement.
The group by would look like
group by computer_id
The having would look like
having report_id= (select max(report_id) )
SELECT operating_systems.operating_system_version,
reports.computer_id,
reports.report_id
FROM operating_systems INNER JOIN reports ON operating_systems.report_id = reports.computer_id
WHERE NOT EXISTS (SELECT 1
FROM reports r2
WHERE r2.computer_id = reports.computer_id
AND r2.reports_id > reports.reports_id)
A subquery would lead you to desired end result:
SELECT os.operating_system_version,
r2.computer_id,
MAX(r2.report_id)
FROM (
SELECT DISTINCT computer_id
FROM reports
) r
INNER JOIN operating_systems os
ON os.report_id = r.computer_id
INNER JOIN reports r2
ON r2.computer_id = r.computer_id
Need to do a better job looking through other posts. This question is answered in an excellent post at: SQL Select only rows with Max Value on a Column

MySQL How can I add values of a column together and remove the duplicate rows?

Good day,
I have a MySQL table which has some duplicate rows that have to be removed while adding a value from one column in the duplicated rows to the original.
The problem was caused when another column had the wrong values and that is now fixed but it left the balances split among different rows which have to be added together. The newer rows that were added must then be removed.
In this example, the userid column determines if they are duplicates (or triplicates). userid 6 is duplicated and userid 3 is triplicated.
As an example for userid 3 it has to add up all balances from rows 3, 11 and 13 and has to put that total into row 3 and then remove rows 11 and 13. The balance columns of both of those have to be added together into the original, lower ID row and the newer, higher ID rows must be removed.
ID | balance | userid
---------------------
1 | 10 | 1
2 | 15 | 2
3 | 300 | 3
4 | 80 | 4
5 | 0 | 5
6 | 65 | 6
7 | 178 | 7
8 | 201 | 8
9 | 92 | 9
10 | 0 | 10
11 | 140 | 3
12 | 46 | 6
13 | 30 | 3
I hope that is clear enough and that I have provided enough info. Thanks =)
Two steps.
1. Update:
UPDATE
tableX AS t
JOIN
( SELECT userid
, MIN(id) AS min_id
, SUM(balance) AS sum_balance
FROM tableX
GROUP BY userid
) AS c
ON t.userid = c.userid
SET
t.balance = CASE WHEN t.id = c.min_id
THEN c.sum_balance
ELSE 0
END ;
2. Remove the extra rows:
DELETE t
FROM
tableX AS t
JOIN
( SELECT userid
, MIN(id) AS min_id
FROM tableX
GROUP BY userid
) AS c
ON t.userid = c.userid
AND t.id > c.min_id
WHERE
t.balance = 0 ;
Once you have this solved, it would be good to add a UNIQUE constraint on userid as it seems you want to be storing the balance for each user here. That will avoid any duplicates in the future. You could also remove the (useless?) id column.
SELECT SUM(balance)
FROM your_table
GROUP BY userid
Should work, but the comment saying fix the table is really the best approach.
You can create a table with the same structure and transfer the data to it with this query
insert into newPriceTable(id, userid, balance)
select u.id, p.userid, sum(balance) as summation
from price p
join (
select userid, min(id) as id from price group by userid
) u ON p.userid = u.userid
group by p.userid
Play around the query here: http://sqlfiddle.com/#!2/4bb58/2
Work is mainly done in MSSQL but you should be able to convert the syntax.
Using a GROUP BY UserID you can SUM() the Balance, join that back to your main table to update the balance across all the duplicates. Finally you can use RANK() to order your duplicate Userids and preserve only the earliest values.
I'd select all this into a new table and if it looks good, deprecate your old table and rename then new one.
http://sqlfiddle.com/#!3/068ee/2

how to find duplicate count without counting original

I need to count the number of duplicate emails in a mysql database, but without counting the first one (considered the original). In this table, the query result should be the single value "3" (2 duplicate x#q.com plus 1 duplicate f#q.com).
TABLE
ID | Name | Email
1 | Mike | x#q.com
2 | Peter | p#q.com
3 | Mike | x#q.com
4 | Mike | x#q.com
5 | Frank | f#q.com
6 | Jim | f#q.com
My current query produces not one number, but multiple rows, one per email address regardless of how many duplicates of this email are in the table:
SELECT value, count(lds1.leadid) FROM leads_form_element lds1 LEFT JOIN leads lds2 ON lds1.leadID = lds2.leadID
WHERE lds2.typesID = "31" AND lds1.formElementID = '97'
GROUP BY lds1.value HAVING ( COUNT(lds1.value) > 1 )
It's not one query so I'm not sure if it would work in your case, but you could do one query to select the total number of rows, a second query to select distinct email addresses, and subtract the two. This would give you the total number of duplicates...
select count(*) from someTable;
select count(distinct Email) from someTable;
In fact, I don't know if this will work, but you could try doing it all in one query:
select (count(*)-(count(distinct Email))) from someTable
Like I said, untested, but let me know if it works for you.
Try doing a group by in a sub query and then summing up. Something like:
select sum(tot)
from
(
select email, count(1)-1 as tot
from table
group by email
having count(1) > 1
)