Parallel SQL queries with aligned data, in MS Access - sql

I have three tables, fruit, person and vegetable
Person
personID personName
-------- ----------
1 Ken
Fruit
personID fruitname
-------- -----
1 apple
1 orange
Vegetable
personID vegetableName
-------- -------------
1 carrot
1 tomato
1 potato
And I want the output to be like this...
personName fruitName vegetableName
---------- --------- -------------
1 apple carrot
1 orange tomato
1 potato
It lessen the duplication of outputs.. is this even possible? can when I tried it before
the values keep repeating? Is their a way to avoid it?

This is only possible if you also add a "position" column to the fruit and vegetables tables, and use this as an additional join column.
Records are not sorted in SQL. So, if you want the sorted, you ALWAYS need a sort criteria, because the SQL standard does not enforce any kind of sort order else.
If an alphabetical sort order is enought, you could dynamically add a position column by something like this (will not work in MS ACCESS, but something similar will do):
SELECT f1.personid, f1.fruitname, count(*) as position
FROM fruit f1 outer join fruit f2 on f1.fruitname = f2.fruitname
and f1.personid = f2.personid
WHERE f2.fruitname < f1.fruitname
GROUP BY f1.personid, f1.fruitname
This query has a position, starting from 0, with the names "before".
Now you can do something like:
select f.personid, f.fruitname, v.vegetablename
from (*fruitquery*) f outer join (*vegetaryquery*) v on f.personid = v.personid
and f.positionid = v.positionid;

Related

How Do I Filter My Results Based Off Of Other Entries?

I have written a statement that retrieves the person name, as well as the food they've eaten.
Person | Food Eaten
John | Cake
Jack | Ice Cream
Louis | Hot Dog
John | Pineapple Pizza
Now that I've retrieved what foods people have eaten, I would like to remove anyone who has eaten Pineapple Pizza from my list.
What type of clause would I want to use to create a unique list of people who haven't eaten Pineapple Pizza?
You can use not exists :
select t.*
from table t
where not exists (select 1
from table t1
where t1.person = t.person and t1.food = 'Pineapple Pizza'
);
If you know the exact value of the food people have eaten, you can exclude it when you write your WHERE clause.
SELECT t.person, t.food_eaten
FROM eaten_tbl t
WHERE t.food_eaten <> 'Pineapple Pizza';

Using a query to return the most frequent value and the count within a group using SQL in MS Access

Say I have a table showing the type of fruit consumed by an individual over a 24 hour period that looks like this:
Name Fruit
Tim Apple
Tim Orange
Tim Orange
Tim Orange
Lisa Peach
Lisa Apple
Lisa Peach
Eric Plum
Eric Orange
Eric Plum
How would I get a table that shows only the most consumed fruit for each person, as well as the number of fruits consumed. In other words, a table that looks like this:
Name Fruit Number
Tim Orange 3
Lisa Peach 2
Eric Plum 2
I tried
SELECT Name, Fruit, Count(Fruit)
FROM table
GROUP BY Name
But that returns an error because Name needs to be in the GROUP BY statement as well. Every other method I've tried returns the counts for ALL values rather than just the maximum values. MAX(COUNT()) doesn't appear to be a valid statement, so I'm not sure what else to do.
This is a pain, but you can do it. Start with your query and then use join:
SELECT n.Name, n.Fruit
FROM (SELECT Name, Fruit, Count(Fruit) as cnt
FROM table as t
GROUP BY Name, Fruit
) as t INNER JOIN
(SELECT Name, max(cnt) as maxcnt
FROM (SELECT Name, Fruit, Count(Fruit) as cnt
FROM table
GROUP BY Name, Fruit
) as t
GROUP BY Name
) as n
ON t.name = n.name and t.cnt = n.maxcnt;

How do I save multiple values and extra and use them in Sqlite?

I have 2 tables e.g.
First table
ID Value
1 Apple
2 Orange
3 Banana## ...
Second Table
PERSON FRUIT
Amy 1
Peter 2
Charlie 1,2
Dick 2,3
I would like to for example save what fruits the users have in just one column. So that when I call out what Charlie wants, I can somehow receive and output of Apple, Orange; and for Dick - Orange, Banana etc.
I am not really sure where to start on achieving this. Is it possible to do it purely in an SQL select statement alone?
You could implement a link table. For example.. you have a Fruit Table, which stores all the unique fruits, and you have a Person table that stores all unique people.
So you should create a third table that links unique fruits to people for example...
ID FRUIT PERSON
1 1 1
2 1 2
3 2 1
etc... then a select on the link table with the person ID, would bring up all the fruits that person likes.

SELECT DISTINCT HAVING Count unique conditions

I've searched for an answer on this but can't find quite how to get this distinct recordset based on a condition. I have a table with the following sample data:
Type Color Location Supplier
---- ----- -------- --------
Apple Green New York ABC
Apple Green New York XYZ
Apple Green Los Angeles ABC
Apple Red Chicago ABC
Apple Red Chicago XYZ
Apple Red Chicago DEF
Banana Yellow Miami ABC
Banana Yellow Miami DEF
Banana Yellow Miami XYZ
Banana Yellow Atlanta ABC
I'd like to create a query that shows the count of unique locations for each distinct Type+Color where the number of unique locations is more than 1, e.g.
Type Color UniqueLocations
---- ----- --------
Apple Green 2
Banana Yellow 2
Note that {Apple, Red, 1} doesn't appear because there is only 1 location for red apples (Chicago). I think I've got this one (but perhaps there is a simpler method). I'm using:
SELECT Type, Color, Count(Location) FROM
(SELECT DISTINCT Type, Color, Location FROM MyTable)
GROUP BY Type, Color HAVING Count(Location)>1;
How can I create another query that lists the Type, Color, and Location for each distinct Type,Color when the count of unique locations for that Type,Color is greater than 1? The resulting recordset would look like:
Type Color Location
---- ----- --------
Apple Green New York
Apple Green Los Angeles
Banana Yellow Miami
Banana Yellow Atlanta
Note that Apple, Red, Chicago doesn't appear because there is only 1 location for red apples. Thanks!
Use a COUNT(DISTINCT Location) and join against a subquery on Type and Color The GROUP BY and HAVING clauses as you have attempted to use them will do the job.
/* Be sure to use DISTINCT in the outer query to de-dup */
SELECT DISTINCT
MyTable.Type,
MyTable.Color,
Location
FROM
MyTable
INNER JOIN (
/* Joined subquery returns type,color pairs having COUNT(DISTINCT Location) > 1 */
SELECT
Type,
Color,
/* Don't actually need to select this value - it could just be in the HAVING */
COUNT(DISTINCT Location) AS UniqueLocations
FROM
MyTable
GROUP BY Type, Color
/* Note: Some RDBMS won't allow the alias here and you
would have to use the expanded form
HAVING COUNT(DISTINCT Location) > 1
*/
HAVING UniqueLocations > 1
/* JOIN back against the main table on Type, Color */
) subq ON MyTable.Type = subq.Type AND MyTable.Color = subq.Color
Here is a demonstration
You could write your first query as this:
Select Type, Color, Count(Distinct Location) As UniqueLocations
From Table
Group By Type, Color
Having Count(Distinct Location) > 1
(if you're using MySQL you could use the alias UniqueLocations in your having clause, but on many other systems the aliases are not yet available as the having clause is evaluated before the select clause, in this case you have to repeat the count on both clauses).
And for the second one, there are many different ways to write that, this could be one:
Select Distinct Type, Color, Location
From Table
Where
Exists (
Select
*
From
Table Table_1
Where
Table_1.Type = Table.Type
and Table_1.Color = Table.Color
Group By
Type, Color
Having
Count(Distinct Location) > 1
)

Group by with count

Say I have a table like this in my MsSql server 2005 server
Apples
+ Id
+ Brand
+ HasWorms
Now I want an overview of the number of apples that have worms in them per brand.
Actually even better would be a list of all the apple brands with a flag if they are unspoiled or not.
So if I had the data
ID| Brand | HasWorms
---------------------------
1 | Granny Smith | 1
2 | Granny Smith | 0
3 | Granny Smith | 1
4 | Jonagold | 0
5 | Jonagold | 0
6 | Gala | 1
7 | Gala | 1
I want to end up with
Brand | IsUnspoiled
--------------------------
Granny Smith | 0
Jonagold | 1
Gala | 0
I figure I should first
select brand, numberOfSpoiles =
case
when count([someMagic]) > 0 then 1
else 0
end
from apples
group by brand
I can't use a having clause, because then brands without valid entries would dissapear from my list (I wouldn't see the entry Gala).
Then I thought a subquery of some kind should do it, but then I can't link the apple id of the outer (grouped) query to the inner (count) query...
Any ideas?
select brand, case when sum(hasworms)>0 then 0 else 1 end IsUnSpoiled
from apples
group by brand
SQL server version, I did spoiled instead of unspoiled, this way I could use the SIGN function and make the code shorter
table + data (DML + DDL)
create table Apples(id int,brand varchar(20),HasWorms bit)
insert Apples values(1,'Granny Smith',1)
insert Apples values(2,'Granny Smith',0)
insert Apples values(3,'Granny Smith',1)
insert Apples values(4,'Jonagold',0)
insert Apples values(5,'Jonagold',0)
insert Apples values(6,'Gala',1)
insert Apples values(7,'Gala',1)
Query
select brand, IsSpoiled = sign(sum(convert(int,hasworms)))
from apples
group by brand
Output
brand IsSpoiled
----------------------
Gala 1
Granny Smith 1
Jonagold 0
SELECT Brand,
1-MAX(HasWorms) AS IsUnspoiled
FROM apples
GROUP BY Brand
SELECT brand,
COALESCE(
(
SELECT TOP 1 0
FROM apples ai
WHERE ai.brand = ao.brand
AND hasWorms = 1
), 1) AS isUnspoiled
FROM (
SELECT DISTINCT brand
FROM apples
) ao
If you have an index on (brand, hasWorms), this query will be super fast, since it does not count aggregates, but instead searches for a first spoiled apple within each brand ans stops.
I haven't tested this, and maybe I'm missing something. But wouldn't this work?
SELECT Brand, SUM(CONVERT(int, HasWorms)) AS SpoiledCount
FROM Apples
GROUP BY Brand
ORDER BY SpoiledCount DESC
I assume HasWorms is a bit field, hence the CONVERT statement. This should return a list of brands with the count of spoiled apples per brand. You should see the worst (most spoiled) at the top and the best at the bottom.
There are many ways to skin this cat. Depending on your RDBMS, different queries will give you the best results. On our Oracle box, this query performs faster than all the others listed, assuming that you have an index on Brand in the Apples table (an index on Brand, HasWorms is even faster, but that may not be likely; depending on your data distribution, an index on just HasWorms may be the fastest of all). It also assumes you have a table "BrandTable", which just has the brands:
SELECT Brand
, 1 IsSpoiled
FROM BrandTable b
WHERE EXISTS
( SELECT 1
FROM Apples a
WHERE a.brand = b.brand
AND a.HasWorms = 1
)
UNION
SELECT Brand
, 0
FROM BrandTable b
WHERE NOT EXISTS
( SELECT 1
FROM Apples a
WHERE a.brand = b.brand
AND a.HasWorms = 1
)
ORDER BY 1;
SELECT CASE WHEN SUM(HasWorms) > 0 THEN 0 ELSE 1 END AS IsUnspoiled, Brand
FROM apples
GROUP BY Brand