I have 1 table "Products" that looks like this:
ID Product Shop Color
01 Car A Black
02 Car B Black
03 Bike C Red
04 Plane A Silver
05 Car C Black
06 Bike A Red
In this example, a Product always has the same color, independent from the Shop where it is sold.
I want to make a query, that returns a distinct set of products, with the Color property. I also will need to have an ID, it could be any ID, that allows me to do a follow up query.
The result of the query should be:
ID Product Color
01 Car Black
03 Bike Red
04 Plane Silver
I tried:
SELECT DISTINCT
Product, Color
FROM
Products
But that obviously doesn't return the ID as well
I guess I need to join something, but my knowledge of SQL is too poor. I hope this is something simple.
This would be one way of getting the result you want:
SELECT min(ID), Product, Color FROM table GROUP BY Product, Color;
How About
SELECT
Product, Color, Min(ID)
FROM
TABLE
GROUP BY
Product, Colour
That'll return unique Product/Color Combinations and the first (lowest) ID found.
You need to use the GROUP BY clause.
The same but obtaining the maximun ID:
SELECT MAX(ID) AS ID, Product, Color
FROM Products
GROUP BY Product, Color
ORDER BY ID
Related
I want to select all the rows of carInventory table but have the brands which has a car in some sort of blue to be first. After, the cars in each brand sorts by year.
I was trying to alter the solution that was given in this post Take precedence on a specific value from a table
but I can't seem to keep the brands together after I figure out the rank
SELECT
*, RANK() over(
partition by colBrand
order by case when colColor like '%blue%' then 1 else 0 end
) RANK FROM inventoryTable Order By Rank, colBrand, colYear
Here's what the tables should look like. Starting Table
Brand
Make
Color
Year
Toyota
Corolla
Atlantis Blue
2015
Ford
Focus
Bayside Blue
2016
Porshe
Taycan
Grey
2019
Volkswagen
Taos
Blue
2015
Volkswagen
Jetta
White
2020
Ford
Focus
Aztec Red
2018
Search Result
Brand
Make
Color
Year
Ford
Focus
Aztec Red
2018
Ford
Focus
Bayside Blue
2016
Toyota
Corolla
Atlantis Blue
2015
Volkswagen
Taos
Blue
2020
Volkswagen
Jetta
White
2015
Porshe
Taycan
Grey
2019
Firstly, the auto industry uses the terms Make and Model to refer to what you call Brand and Make. Using your own terminology will be confusing to many.
I think if you write your order logic more precisely and completely, you will more easily find a path to a solution. And it helps to be consistent. What is "ColBrand"? ColYear? IMO you do everyone a disservice by prefacing column names with a redundant prefix. And here "col" refers to "column"? Just don't!
So it seems you want to sort by <brands with blue vehicles / brands without>, brand, year descending. Notice that Make is not included in your ordering. And notice that your Taos has year 2015 in the table but swaps that year for another in the desired output. This is one reason why you should post a script - helps to avoid typos like that and encourages others to help you.
So here is another way to accomplish that. The CTE selects all brands that have blue colors. You simply outer join the actual table to the CTE to know if the brand satisfies the blue condition. Use that knowledge in the CASE expression in the ORDER BY clause.
with blubr as (select distinct brand from #inventory where color like '%blue%')
select inv.brand, inv.make, inv.color, inv.year
from #inventory as inv left join blubr on inv.brand = blubr.brand
order by case when blubr.brand is not null then 0 else 1 end,
inv.brand, inv.year desc
;
fiddle to demonstrate Note there is a flaw in the logic of the prior answer. I've added a row to illustrate it. Do you see it? It is an easy fix to that query. Is this query better? Not really but it hopefully helps you think of different approaches to achieving the same goal.
Interesting, maybe below query can do what you need
I also made a demo fiddle
select *
from inventoryTable i
order by
case when exists ( select 1 from inventoryTable t
where t.colbrand=i.colbrand and t.colcolor like '%blue%') then 9999
else colYear end desc,colBrand asc, colyear desc
Suppose I have a table, cars, which looks like this:
id | model | car_color
----+--------+--------
01 | Camry | blue
02 | Elantra| red
03 | Sienna | blue
04 | Camry | fuschia
05 | LX450 | pink
06 | Tundra | lime
Also suppose I have this other table, a non-exhaustive of colors, colors:
colors
-------
blue
red
fuschia
In Postgres (or perhaps in any SQL variant), how can I count how many entries in cars.car_color match any of the entries in colors.colors?
The answer here would be 4, as 'pink' and 'lime' don't appear in the colors table, but I can't get Postgres to spit this back for me. (In what I'm actually working on, the first table has dozens of millions of rows, and the second table I'm checking against has about 100k.) I'm trying things like this, to no avail:
select count(*) from cars
where "car_color" IN (colors.colors)
Here's the error:
[42P01] ERROR: missing FROM-clause entry for table "colors"
My intuition is that this is something about my WHERE statement, but I can't figure out what. Nor can I seem to phrase this in such a way as to get good search results in Google or SX search -- I know I'm not the first (or the 257th) to ask this.
Close. You need a subquery:
select count(*)
from cars c
where c.car_color IN (select co.color from colors co);
Postgres as a good optimizer, but sometimes exists works better:
select count(*)
from cars c
where exists (select 1 from colors co where co.color = c.car_color);
Here is a db<>fiddle.
I have a request which I can accomplish in code but am wondering if it is at all possible do do on SQL alone. I have a products table that has a Category column and a Price column. What I want to achieve is all of the products grouped together by Category, and then ordered by the cheapest to most expensive in both the category and all the categories combined. So for example :
Category | Price
--------------|---------------------
Basin | 500
Basin | 700
Basin | 750
Accessories | 550
Accessories | 700
Accessories | 1000
Bath | 700
As you can see the cheapest item is a basin for 500, then an Accessory for 550 then a bath for 700. So I need the categories of products to be sorted by their cheapest item, and then each category itself in turn to be sorted cheapest to most expensive.
I have tried partitioning, grouping sets ( which i know nothing about ) but still no luck so eventually resorted to my strength ( C# ) but would prefer to do it straight in SQL if possible. One last side note : This query is hit quite often so performance is key so if possible i would like to avoid temp tables / cursors etc
I think using MIN() with a window (OVER) makes it clearest what the intent is:
declare #t table (Category varchar(19) not null,Price int not null)
insert into #t (Category,Price) values
('Basin',500),
('Basin',700),
('Basin',750),
('Accessories',550),
('Accessories',700),
('Accessories',1000),
('Bath',700)
;With FindLowest as (
select *,
MIN(Price) OVER (PARTITION BY Category) as Lowest
from
#t
)
select * from FindLowest
order by Lowest,Category,Price
If two categories share the same lowest price, this will still keep the two categories separate and sort them alphabetically.
Select...
Order by category, price desc
SELECT p.category,p.price
FROM products p,(select category,min(price) mn from products group by category order by mn) tab1
WHERE p.category=tab1.category
GROUP BY p.category,p.price,tab1.mn
order by tab1.mn,p.category;
Is this what you want?
I think, you do not need GROUP BY clause in your query. If I got your goal correctly, you can try by substituting actual categories in your ORDER BY clause with the minimum price per category inside the subquery.That will allow you getting all the categories sequential, i.e. not Basin - 500; Accessories - 550, but everything for Basin first. After that, you can group by ordinary Price inside each category.
SELECT *
FROM products p
ORDER BY
(SELECT MIN(Price) FROM products p2 WHERE p2.Category=p.Category
),
Price;
So I got this query and it's pulling from tables like this:
Plantation TABLE
PLANT ID, Color Description
1 Red
2 Green
3 Purple
Vegetable Table
VegetabkeID, PLANT ID, Feeldesc
199 1 Harsh
200 1 Sticky
201 2 Bitter
202 3 Bland
and now in my Query I join them using PLANT ID ( I Use a left join)
PLANT ID, Color Description, Feeldesc
1 Red Harsh
1 Red Sticky
2 Green Bitter
3 Purple Bland
So the problem is that in the Query you can see Red shows up twice! I can't have this, and
I'm not sure how to make the joins happen but stop reds from coming up twice.
It seems remotely possible that you're asking how do to group indication -- that is, showing a value which identifies or describes a group only on the first line of that group. In that case, you want to use the lag() window function.
Assuming setup of the schema and data is like this:
create table plant (plantId int not null primary key, color text not null);
create table vegetable (vegetableId int not null, plantId int not null,
Feeldesc text not null, primary key (vegetableId, plantId));
insert into plant values (1,'Red'),(2,'Green'),(3,'Purple');
insert into vegetable values (199,1,'Harsh'),(200,1,'Sticky'),
(201,2,'Bitter'),(202,3,'Bland');
The results you show (modulus column headings) could be obtained with this simple query:
select p.plantId, p.color, v.Feeldesc
from plant p left join vegetable v using (plantId)
order by plantId, vegetableId;
If you're looking to suppress display of the repeated information after the first line, this query will do it:
select
case when plantId = lag(plantId) over w then null
else plantId end as plantId,
case when p.color = lag(p.color) over w then null
else p.color end as color,
v.Feeldesc
from plant p left join vegetable v using (plantId)
window w as (partition by plantId order by vegetableId);
The results look like this:
plantid | color | feeldesc
---------+--------+----------
1 | Red | Harsh
| | Sticky
2 | Green | Bitter
3 | Purple | Bland
(4 rows)
I had to do something like the above just this week to produce a listing directly out of psql which was easy for the end user to read; otherwise it never would have occurred to me that you might be asking about this functionality. Hopefully this answers your question, although I might be completely off base.
Check array_agg function in the documentation it can be used something like this:
SELECT
v.plantId
,v.color
,array_to_string(array_agg(v.Feeldesc),', ')
FROM
vegetable
INNER JOIN plant USING (plantId)
GROUP BY
v.plantId
,v.color
or use
SELECT DISTINCT
v.plantId
,v.color
FROM
vegetable
INNER JOIN plant USING (plantId)
disclaimer: hand written, syntax errors expected :)
I cant seem to group by multiple data fields and sum a particular grouped column.
I want to group Person to customer and then group customer to price and then sum price. The person with the highest combined sum(price) should be listed in ascending order.
Example:
table customer
-----------
customer | common_id
green 2
blue 2
orange 1
table invoice
----------
person | price | common_id
bob 2330 1
greg 360 2
greg 170 2
SELECT DISTINCT
min(person) As person,min(customer) AS customer, sum(price) as price
FROM invoice a LEFT JOIN customer b ON a.common_id = b.common_id
GROUP BY customer,price
ORDER BY person
The results I desire are:
**BOB:**
Orange, $2230
**GREG:**
green, $360
blue,$170
The colors are the customer, that GREG and Bob handle. Each color has a price.
There are two issues that I can see. One is a bit picky, and one is quite fundamental.
Presentation of data in SQL
SQL returns tabular data sets. It's not able to return sub-sets with headings, looking something a Pivot Table.
The means that this is not possible...
**BOB:**
Orange, $2230
**GREG:**
green, $360
blue, $170
But that this is possible...
Bob, Orange, $2230
Greg, Green, $360
Greg, Blue, $170
Relating data
I can visually see how you relate the data together...
table customer table invoice
-------------- -------------
customer | common_id person | price |common_id
green 2 greg 360 2
blue 2 greg 170 2
orange 1 bob 2330 1
But SQL doesn't have any implied ordering. Things can only be related if an expression can state that they are related. For example, the following is equally possible...
table customer table invoice
-------------- -------------
customer | common_id person | price |common_id
green 2 greg 170 2 \ These two have
blue 2 greg 360 2 / been swapped
orange 1 bob 2330 1
This means that you need rules (and likely additional fields) that explicitly state which customer record matches which invoice record, especially when there are multiples in both with the same common_id.
An example of a rule could be, the lowest price always matches with the first customer alphabetically. But then, what happens if you have three records in customer for common_id = 2, but only two records in invoice for common_id = 2? Or do the number of records always match, and do you enforce that?
Most likely you need an extra piece (or pieces) of information to know which records relate to each other.
you should group by using all your selected fields except sum then maybe the function group_concat (mysql) can help you in concatenating resulting rows of the group clause
Im not sure how you could possibly do this. Greg has 2 colors, AND 2 prices, how do you determine which goes with which?
Greg Blue 170 or Greg Blue 360 ???? or attaching the Green to either price?
I think the colors need to have unique identofiers, seperate from the person unique identofiers.
Just a thought.