SQL: how to select where one column does not match another column for ALL records within a given group - mysql

I have a table named sales in a MySQL database that looks like this:
company manufactured shipped
Mercedes Germany United States
Mercedes Germany Germany
Mercedes Germany United States
Toyota Japan Canada
Toyota Japan England
Audi Germany United States
Audi Germany France
Audi Germany Canada
Tesla United States Mexico
Tesla United States Canada
Tesla United States United States
Here is a Fiddle: http://www.sqlfiddle.com/#!17/145ff/3
I would like to return the list of companies that ship ALL of their products internationally (that is, where the value in the manufactured column differs from the value in the shipped column for ALL records of a particular company).
Using the example above, the desired result set would be:
company
Toyota
Audi
Here is my (hackish) attempt:
WITH temp_table AS (
SELECT
s.company AS company
, SUM(CASE
WHEN s.manufactured != s.shipped THEN 1
ELSE 0
END
) AS count_international
, COUNT(s.company) AS total_within_company
FROM
sales s
GROUP BY
s.company
)
SELECT
company
FROM
temp_table
WHERE count_international = total_within_company
Essentially, I count the instances where the columns do not match. Then I check whether the sum of those mismatched instances matches the number of records within a given group.
This approach works, but it's far from an elegant solution!
Can anyone offer advice as to a more idiomatic way to implement this query?
Thanks!

We can GROUP BY company and use a HAVING clause to say all countries in shipped must differ to the country in manufactured:
SELECT company
FROM sales
GROUP BY company
HAVING COUNT(CASE WHEN manufactured = shipped THEN 1 END) = 0;
Try out here: db<>fiddle
The fiddle linked in the question is a Postgres DB, but MySQL is taged as DBMS.
In a MySQL DB, the above query can be simplified to:
SELECT company
FROM sales
GROUP BY company
HAVING SUM(manufactured = shipped) = 0;
In a Postgres DB, this is not possible.

You have to think in sets... you want to display all without a match -- find the matches display the rest
SELECT DISTINCT company
FROM sales
WHERE company NOT IN (
SELECT company
FROM sales
WHERE manufactured = shipped
)

Related

Fetch fixed set of duplicate records from table

I want to fetch records from a table that contains duplicate records. I want the output to be like only two duplicate records from each set of duplicate records in overall record output set.
example-
Name
Country
John
India
Mark
India
Chris
Russia
Feggy
England
Rain
Russia
Monesy
Russia
Bhumi
India
Peter
England
Bruice
England
Radhe
India
Output should have only two duplicate set of records from all duplicate of similar type as we can see in output below the country is repeating only two times and it took only first two counters of duplicate records in final record set -
Name
Country
John
India
Mark
India
Chris
Russia
Feggy
England
Rain
Russia
Peter
England
You can number the lines by the window and select only the first N.
Sorting should be chosen according to the business logic of the query.
For example:
;WITH numbered_name AS
(
SELECT *
, ROW_NUMBER() OVER (PARTITION BY t.Country ORDER BY t.Name) rn
FROM table t
)
SELECT Name
, Country
FROM numbered_name
WHERE rn <= 2

Data warehouse logical model

I have drawn a logical model for a hotel room booking OLTP system Logical model
I'm facing a problem querying it.
the question is: For each Country and quarter, produce the cumulative income of 3-star-rooms
Noted that RoomBand contain how many starts for each room
I have tried this
SELECT Quarter, Country
FROM DT_Date, Country, RoomBand
where RoomBand = 3
the output was this
CountyName Quarter
USA 2
Uk 1
USA 2
UK 1
as it has shown it repeated USA and UK
why is that happening
Thanks for the support all
Try the DISTINCT operator with your query. For example: SELECT DISTINCT column1, column2, .... You can read more about it here.

How to get results from Mysql database using WHERE if there is more than 1 criterion for identification?

id points year country
-----------------------------------
1 45 1998 Mexico
2 45 2000 Germany
3 47 2010 Russia
4 45 1970 China
5 49 2010 Austria
I wonder how can I take row results considering only 2 items from country column. For example only records where country is Germany and Mexico. When I try to get results where only 1 country is criterion the thing is easy:
SELECT * FROM List WHERE Country='Mexico';
the result is:
id points year country
-----------------------------------
1 45 1998 Mexico
but when I try to get results where 2 country items are criteria problems start. I tried:
SELECT * FROM List WHERE country='Mexico' AND Country='Germany';
SELECT * FROM List WHERE country='Mexico' AND 'Germany';
SELECT * FROM List WHERE country='Mexico','Germany';
SELECT * FROM List WHERE country='Mexico'AND WHERE country='Germany';
but no desired result:
id points year country
-----------------------------------
1 45 1998 Mexico
2 45 2000 Germany
I understand that maybe I committed logical error because there is no single record where country is Mexico and Germany at same time, and sql maybe understands claim exactly that way, but, how to write correctly in sql language: Give me results for records where countries are Mexico and Germany. Thanks.
You are looking for IN operator
SELECT * FROM List WHERE Country in ('Mexico','Germany');
Just use OR.
So instead of
SELECT * FROM List WHERE country='Mexico' AND Country='Germany';
it would be
SELECT * FROM List WHERE country='Mexico' OR country='Germany';
IN is also a good function to use, especially if you've got multiple values that you want to check against but that's been covered in the other answers.
You need to use or or in, you have been using and and asking mysql to find a row where country is both Mexico and Germany which is not true.
SELECT * FROM List WHERE Country in ('Mexico','Germany');
try this:
SELECT * FROM List WHERE country='Mexico' OR Country='Germany';
SQL is using logic. Natural language is not.
When you say that you want the results for a list of countries you need to specify so. This request corresponds to an logical or. Since the name can be one or the other, both are correct.
SELECT * FROM List WHERE Country = 'Mexico' OR Country = 'Germany'
To prevent further mistakes like these, I recommend that you look up logical operations in the docs (they are very good). MySQL or the PostGres, both should be fine.

Getting data from multiple tables into single row while concatenating some values

I'm trying to retrieve data from tables and combine multiple rows into a single column, without repeating any information.
I have the following tables: profile, qualification, projects.
Profile
pro_id surname firstname
------ ------- ----------
1 John James
2 King Fred
3 Luxury-Yachts Raymond
Qualification
pro_id Degree School Year
------ ------ ------ -----
1 MBA Wharton university 2002
1 LLB Yale University 2001
2 BSc Covington University 1998
2 BEd Kellog University 1995
Projects
pro_id Title Year
------ ------ ------
1 Social Networking 2003
1 Excavation of aquatic debris 2007
2 Design of solar radios 1992
2 Development of expert systems 2011
I want to retrieve the all of the information for each person, with each person appearing only once in the result. The info on qualifications and projects should each be in their own column (one column for qualifications, another for projects), separated by commas. For example, the results for the above sample data should be:
1 John James MBA Wharton university 2002, LLB Yale University 2001 Social Networking 2003, Excavation of aquatic debris 2007, Design of Solar panels 2008
2 King Fred BSc Covington University 1998, BEd Kellog University 1995, Msc MIT 2011 Design of solar radios 1992, Development of expert systems 2011
3 Raymond Luxury-Yachts
Currently, I have the query:
SELECT pro_id,
surname,
firstname,
group_concat(degree,school,year) AS qual,
concat(Title,year) AS work
FROM profile,
LEFT JOIN qualification
ON qualification.pro_id = profile.pro_id
JOIN projects
ON projects.pro_id = profile.pro_id
GROUP BY pro_id
For the sample data, this query results in:
1 John James MBA Wharton university 2002, Social Networking 2003
1 John James LLB Yale University 2001, Excavation of aquatic debris 2007
1 John James MBA Wharton university 2002, Social Networking 2003, Excavation of aquatic debris 2007
etc
Note: Raymond Luxury-Yachts isn't present in the current result.
I don't want duplicate result records. Also if the surname does not have any entry in the qualification and projects table, I want the query to return the name and display an empty field in the qualification and projects table instead of omitting them altogether.
Replace LEFT JOIN with JOIN
Select pro_id, surname, firstname, group_concat(degree,school,year) as qual,concat(Title,year) as work
from profile
join qualification on qualification.pro_id = profile.pro_id
join projects on projects.pro_id = profile.pro_id group by pro_id
What is the difference between "INNER JOIN" and "OUTER JOIN"?
Using Join will fix the issue with displaying values even if there are no records in the projects table.
For the first question, you can try making a stored function and calling it from the select statement. This function will take pro_id as parameter, create the concatenated string and return it. That's the only solution for MySQL that I can think of at the moment.
I think you are close on your thoughts of group_concat. However, with possible No values (thus leaving nulls), can cause problems. I would have each secondary table pre-concatinated by person's ID and join to THAT result. Eliminates the problem of nulls
SELECT
p.pro_id,
p.surname,
p.firstname,
PreQConcat.UserQual,
PrePJConcat.UserWork
FROM
profile p
LEFT JOIN
( select q.pro_id,
group_concat( q.degree, q.school, q.year) AS UserQual
from
qualification q
group by
q.pro_id ) PreQConcat
ON p.Pro_ID = PreQConcat.pro_id
LEFT JOIN
( select pj.pro_id,
concat(pj.Title, pj.year) AS UserWork
from
projects pj
group by
pj.pro_id ) PrePJConcat
ON p.Pro_ID = PrePJConcat.pro_id
You are going through all people anyhow, and want all their respective elements (when they exist) grouped, so why group on a possibility it doesn't exist. Let the JOINED queries run once each, complete with a single result grouped by only those people it had data for, then join back to the original profile person.

MySQL: Selecting One Record When Others Have Same Data

I have a table of cities that all share the same area code:
367 01451 Harvard Worcester Massachusetts MA 978 Eastern
368 01452 Hubbardston Worcester Massachusetts MA 978 Eastern
369 01453 Leominster Worcester Massachusetts MA 978 Eastern
The table has multiple area codes, all with multiple cities.
What I'd like to do is only select one city from each area code and delete any extra cities from duplicate area codes. What would be the best query to accomplish this?
I believe:
Mysql4: SQL for selecting one or zero record
Is coming close to what I need but didn't quite get what/how those answers were working.
Note The "978" row is the "area_code" row, table name is "zip_code".
DELETE c.*
FROM zip_code c
JOIN (
SELECT area_code, MIN(id) AS mid
FROM zip_code
GROUP BY
area_code
) co
ON c.area_code = co.area_code
AND c.id <> co.mid