How to check if two columns are consistent in a table. sql - sql

I'm struggling to ask the question so I will just put an example table. Basically, if I have two columns with headings person and insured car, how can I check if the same person consistently insures the same brand of car.
------|------
|person|brand |
------|------
| 0 |Toyota|
| 0 |Mazda |
| 1 |Toyota|
| 1 |Toyota|
| 2 |Honda |
| 2 |Honda |
| 3 |Ford |
------|------
So basically in this table I want to filter out person 0 because he insures both Toyota's and Mazda's, however the other people exclusively insure one brand of a car.
Thanks.

If you just want the people and car, you can use aggregation:
select person, min(brand) as the_brand
from t
group by person
having min(brand) = max(brand);

Related

SQL query to count how many values appear N times in a column

I have a table like this, but with 1mi rows:
+------+-----------------+
| TEAM | VISITATION DATE |
+------+-----------------+
| 1 | 02/02/2021 |
| 1 | 04/03/2021 |
| 1 | 10/04/2021 |
| 2 | 13/03/2021 |
| 3 | 01/03/2021 |
| 3 | 27/04/2021 |
| 4 | 21/02/2021 |
| 4 | 14/03/2021 |
| 4 | 01/04/2021 |
+------+-----------------+
And I want to know how many TEAMS were visited N times.
For instance, if I want to know how many TEAMS were visited once, the result would be 1 (because only team 2 was). If i wanted three times, result would be 2 (because both team 1 and 4 were visited three times).
It would be something like
SELECT COUNT(TEAM)
FROM table
WHERE COUNT(VISITATION DATE)=1
(then =2, =3, and so on)... But since I can't use COUNT after WHERE, I don't know how to do it. Can anyone help?
If it helps, it doesn't necessarily need to be connected to the visitation date. It could be "How many TEAMS appear once/twice/three times... (only considering the TEAM column)"
Thanks in advance!
select count(team) from
(select team, COUNT(team) as countTeam from t group by team)
where countTeam = 2
Replace 2 by the number you want.
Demo
With having we have:
select
team,
COUNT(team) as countTeam
from t
group by team
having count(team) = 2
You can use having clause
select
team,
COUNT(TEAM) as total_count
from table
group by
team
having count(team) = 1

Sum of different rows

I am using an ERP that has a semi-"graphical" SQL-based report writer.
The way our software works is that products can be "Masters" or "Members" (or neither, but lets ignore that for now). Essentially a product can be the "parent" of a group or a "child" of another products group. So say you have the following table:
|---------------------|------------------|------------------|
| Product | ProductMaster | Quantity |
|---------------------|------------------|------------------|
| A | | 200 |
|---------------------|------------------|------------------|
| A1 | A | 50 |
|---------------------|------------------|------------------|
| A2 | A | 50 |
|---------------------|------------------|------------------|
| A3 | A | 25 |
|---------------------|------------------|------------------|
Product A is the Master, the others are members of A.
What I would like to do is have one row per product that combines the quantities of Masters and all their Members (in this case, one row with Quantity = 325), and I can't figure out how to do it. I can get the Sum of all the members, by putting Group By ProductMaster, but then I'm stuck.
Assuming that there is only one level of depth, you can use coalesce():
select coalesce(ProductMaster, Product) as ProductMaster, sum(Quantity)
from t
group by coalesce(ProductMaster, Product);
Note: This assumes that blank means NULL. If it means something else, then you'll want a CASE instead of COALESCE().

Calculating Number of Columns that have no Null value

I want to make a table like following
| ID | Sibling1 | Sibling2 | Sibling 3 | Total_Siblings |
______________________________________________________________
| 1 | Tom | Lisa | Null | 2 |
______________________________________________________________
| 2 | Bart | Jason | Nelson | 3 |
______________________________________________________________
| 3 | George | Null | Null | 1 |
______________________________________________________________
| 4 | Null | Null | Null | 0 |
For Sibling1, Sibling2, Sibling3: they are all nvarchar(50) (can't change this as the requirement).
My concern is that how can I calculate the value for Total_Siblings so it will display the number of siblings like above, using SQL? i attempted to use (Sibling1 + Sibling 2) but it does not display the result I want.
Cheers
A query like this would do the trick.
SELECT ID,Sibling1,Sibling2,Sibling3
,COUNT(Sibling1)+Count(Sibling2)+Count(Sibling3) AS Total
FROM MyTable
GROUP BY ID
A little explanation is probably required here. Count with a field name will count the number of non-null values. Since you are grouping by ID, It will only ever return 0 or 1. Now, if you're using anything other than MySQL, you'll have to substitute
GROUP BY ID
FOR
GROUP BY ID,Sibling1,Sibling2,Sibling3
Because most other databases require that you specify all columns that don't contain an aggregate function in the GROUP BY section.
Also, as an aside, you may want to consider changing your database schema to store the siblings in another table, so that each person can have any number of siblings.
You can do this by adding up individual counts:
select id,sibling1,sibling2,sibling3
,count(sibling1)+count(sibling2)+count(sibling3) as total_siblings
from table
group by 1,2,3,4;
However, your table structure makes this scale crappily (what if an id can belong to, say, 50 siblings?). If you store your data into a table with columns of id and sibling, then this query would be as simple as:
select id,count(sibling)
from table
group by id;

MySQL Advanced SELECT help

Alright well I recently got into normalizing my database for this little side project that I have been creating for a while now, but I've just hit a brick wall. I'll try to give an understandable example of what I have and what I need to accomplish ― and hopefully it won't be too painful. OK.
I have 3 tables the first one we will call Shows, structured something like this:
+----+--------------------------+
| id | title |
+----+--------------------------+
| 1 | Example #1 |
| 2 | Example #2 |
| 3 | Example #3 |
+----+--------------------------+
Plain and simple.
My next table is called Categories, and lookes like this:
+----+--------------------------+
| id | category |
+----+--------------------------+
| 1 | Comedy |
| 2 | Drama |
| 3 | Action |
+----+--------------------------+
And a final table called Show_categories:
+---------+---------+
| show_id | cat_id |
+---------+---------+
| 1 | 1 |
| 1 | 3 |
| 2 | 2 |
| 2 | 3 |
| 3 | 1 |
| 3 | 2 |
+---------+---------+
As you may have noticed the problem is the in my database a single show can have multiple categories. Everything is structured fine, except for the fact that I can't find a why to search for show with multiple categories.
If I were to search for action and comedy type shows I would be given Example #1, but it is not possible (at least with my queries), because the cat_id's inside the Show_categories are in different rows.
Example of a working single category search (Selecting all comedy shows):
SELECT s.id,s.title
FROM Shows s JOIN Show_categories sc ON sc.anid=s.id
WHERE sc.cat_id=1 GROUP BY s.id
And a query that is impossible (because cat_id can't equal 2 different things):
SELECT s.id,s.title
FROM Shows s JOIN Show_categories sc ON sc.anid=s.id
WHERE sc.cat_id=1 AND sc.cat_id=2 GROUP BY s.id
So to sum things up what I am asking is how do I handle a query where I am looking for a show based on multiple matching categories.
Use:
SELECT s.id,
s.title
FROM SHOWS s
JOIN SHOW_CATEGORIES sc ON sc.anid = s.id
WHERE sc.cat_id IN (1, 2)
GROUP BY s.id, s.title
HAVING COUNT(DISTINCT sc.cat_id) = 2
The COUNT(DISTINCT sc.cat_id) comparison needs to equal the number of cat_id values listed in the IN clause. But if both the SHOW_CATEGORIES show_id and cat_id columns are either the primary key, or there's a unique constraint on both columns -- then you can use COUNT(sc.cat_id).
You need an OR statement.
SELECT s.id,s.title
FROM Shows s JOIN Show_categories sc ON sc.anid=s.id
WHERE sc.cat_id=1 OR sc.cat_id=2 GROUP BY s.id
That is, you want all shows with either catid 1 OR catid 2. So this query will return 1, 2 and 3.

Retrieve comma delimited data from a field

I've created a form in PHP that collects basic information. I have a list box that allows multiple items selected (i.e. Housing, rent, food, water). If multiple items are selected they are stored in a field called Needs separated by a comma.
I have created a report ordered by the persons needs. The people who only have one need are sorted correctly, but the people who have multiple are sorted exactly as the string passed to the database (i.e. housing, rent, food, water) --> which is not what I want.
Is there a way to separate the multiple values in this field using SQL to count each need instance/occurrence as 1 so that there are no comma delimitations shown in the results?
Your database is not in the first normal form. A non-normalized database will be very problematic to use and to query, as you are actually experiencing.
In general, you should be using at least the following structure. It can still be normalized further, but I hope this gets you going in the right direction:
CREATE TABLE users (
user_id int,
name varchar(100)
);
CREATE TABLE users_needs (
need varchar(100),
user_id int
);
Then you should store the data as follows:
-- TABLE: users
+---------+-------+
| user_id | name |
+---------+-------+
| 1 | joe |
| 2 | peter |
| 3 | steve |
| 4 | clint |
+---------+-------+
-- TABLE: users_needs
+---------+----------+
| need | user_id |
+---------+----------+
| housing | 1 |
| water | 1 |
| food | 1 |
| housing | 2 |
| rent | 2 |
| water | 2 |
| housing | 3 |
+---------+----------+
Note how the users_needs table is defining the relationship between one user and one or many needs (or none at all, as for user number 4.)
To normalise your database further, you should also use another table called needs, and as follows:
-- TABLE: needs
+---------+---------+
| need_id | name |
+---------+---------+
| 1 | housing |
| 2 | water |
| 3 | food |
| 4 | rent |
+---------+---------+
Then the users_needs table should just refer to a candidate key of the needs table instead of repeating the text.
-- TABLE: users_needs (instead of the previous one)
+---------+----------+
| need_id | user_id |
+---------+----------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 1 | 2 |
| 4 | 2 |
| 2 | 2 |
| 1 | 3 |
+---------+----------+
You may also be interested in checking out the following Wikipedia article for further reading about repeating values inside columns:
Wikipedia: First normal form - Repeating groups within columns
UPDATE:
To fully answer your question, if you follow the above guidelines, sorting, counting and aggregating the data should then become straight-forward.
To sort the result-set by needs, you would be able to do the following:
SELECT users.name, needs.name
FROM users
INNER JOIN needs ON (needs.user_id = users.user_id)
ORDER BY needs.name;
You would also be able to count how many needs each user has selected, for example:
SELECT users.name, COUNT(needs.need) as number_of_needs
FROM users
LEFT JOIN needs ON (needs.user_id = users.user_id)
GROUP BY users.user_id, users.name
ORDER BY number_of_needs;
I'm a little confused by the goal. Is this a UI problem or are you just having trouble determining who has multiple needs?
The number of needs is the difference:
Len([Needs]) - Len(Replace([Needs],',','')) + 1
Can you provide more information about the Sort you're trying to accomplish?
UPDATE:
I think these Oracle-based posts may have what you're looking for: post and post. The only difference is that you would probably be better off using the method I list above to find the number of comma-delimited pieces rather than doing the translate(...) that the author suggests. Hope this helps - it's Oracle-based, but I don't see .