Postgres tsvector with relational tables - sql

I have two simple tables. First is brands and each brand may have a top brand. For example Elseve has a top brand which is Loreal Paris. But Avon has no top brand. And I have a simple products table.
Here is sqlfiddle
Here is brands table.
id | name | parent_id | depth
----+--------------+-----------+-------
3 | Loreal Paris | null | 0
1 | Avon | null | 1
2 | Elseve | 3 | 1
(3 rows)
And here is products table
id | brand_id | name
----+----------+-----------
1 | 1 | Product 1
2 | 2 | Product 2
(2 rows)
When I try to get tsvectors, Product 1 document returns null result. But I need to get at least Avon in the document.
product_id | product_name | document
------------+--------------+--------------------------------------------------
1 | Product 1 |
2 | Product 2 | '2':2 'elsev':3 'loreal':4 'paris':5 'product':1
(2 rows)
How to solve this problem ?
Thanks to Voa Tsun. I updated query a little bit. I don't need grouping anymore.
select
products.id as product_id,
products.name as product_name,
to_tsvector(products.name) ||
to_tsvector(brands.name) ||
to_tsvector(top_brands.name)
as document
from products
JOIN brands on brands.id = products.brand_id
LEFT JOIN brands as top_brands on coalesce(brands.parent_id,brands.id) = top_brands.id;

The basic idea is to join id not against null in "parent_id", but "at least against id", as I got from your post.
like here:
select
products.id as product_id,
products.name as product_name,
to_tsvector(coalesce(products.name,brands.name)) ||
to_tsvector(brands.name) ||
to_tsvector(coalesce(string_agg(top_brands.name, ' ')))
as document
from products
JOIN brands on brands.id = products.brand_id
LEFT JOIN brands as top_brands on coalesce(brands.parent_id,brands.id) =
top_brands.id
GROUP BY products.id,brands.id;
product_id product_name document
1 1 Product 1 '1':2'avon':3,4'product':1
2 2 Product 2 '2':2'elsev':3'loreal':4'pari':5'product':1

Related

pull all data only if there are distinct within a group in SQL

I have table with the following columns (product ID, product group code, product category)
I only want to pull the data if there there are two or more unique product category data within each product group. for example I have the following data.
Product id | product group code | product category
1 | a | Apple
2 | a | Orange
3 | a | Apple
4 | b | Toys
5 | b | Toys
I only want to see all the unique product category for each product code. The output i want to see is:
Product id product group code product category
1 | a | Apple
2 | a | Orange
3 | a | Apple
Thanks
I only want to pull the data if there there are two or more unique product category data within each product group. for example I have the following data.
This answer is based on the results you show which is consistent. The paragraph before the results is unclear.
One method is exists:
select t.*
from t
where exists (select 1
from t t2
where t2.product_group = t.product_group and
t2.product_category <> t.product_category
);
How about two nested selects? one grouping and selecting the group that has more than one in COUNT DISTINCT product_group_id, then join the "good group" back to the original input?
WITH
-- your input as an in-line table
input(Product_id,product_group_code,product_category) AS (
SELECT 1,'a','Apple'
UNION ALL SELECT 2,'a','Orange'
UNION ALL SELECT 3,'a','Apple'
UNION ALL SELECT 4,'b','Toys'
UNION ALL SELECT 5,'b','Toys'
)
,
good_grp AS (
SELECT
product_group_code
FROM input
GROUP BY product_group_code
HAVING COUNT(DISTINCT product_category) >1
)
SELECT
i.*
FROM input i
JOIN good_grp USING(product_group_code)
ORDER BY 1
-- returning ...
Product_id | product_group_code | product_category
-----------+--------------------+------------------
1 | a | Apple
2 | a | Orange
3 | a | Apple

change and merge multiple values on column if there is duplicate value in other columns

Sorry, I'm new to SQL..I'm using Sybase Central
I need help, I'm currently stuck on data table from select statement (stored procedure) like this :
select case when product like 'A%' then 'Product A' when product like 'B%'
then 'Product B' else 'Product C' end as
'ProductGroup',product,invoice,customer from data_sales
group by product,invoice,customer
Results :
+--------------+---------+---------+---------+
| ProductGroup | Product | Invoice | Customer|
+--------------+---------+---------+---------+
| Product A | A1 | INV001 | MR.A |
| Product A | A1 | INV002 | MR.B |
| Product B | B1 | INV002 | MR.B |
| Product B | B1 | INV003 | MR.C |
+--------------+---------+---------+---------+
I want to merge and change the value into Product C in ProductGroup column, if there is duplicate values on Invoices or Customers columns
Results should be like this :
+--------------+--------+---------+
| ProductGroup | Invoice| Customer|
+--------------+--------+---------+
| Product A | INV001 | MR.A |
| Product C | INV002 | MR.B |
| Product B | INV003 | MR.C |
+--------------+--------+---------+
I've been using case when and group by method, but it's still showing duplicate results
Any help would be really appreciated
Thank you
The below query does check the invoices or customers for duplicates done via group by. Grouping invoices will group the repeated invoices and will give the aggregate count as greater than 1 if found repeated else 0 similarly in or condition for customers. Is this what you want ?
Update Table
Set Product="Product C" where
Invoice In
(Select Invoice
from table group by
Invoice having
count(*)>1) or
Customers In (Select Customers
from table group by
Customers having
count(*)>1)
You can check the duplicates by having count(*)>1 clause with group by
update tab t
set ProductGroup = 'Product C'
where exists (
select 1
from tab tt
where exists ( select Invoice
from tab
where Invoice = tt.Invoice
group by Invoice
having count(*)>1 )
or exists ( select Customer
from tab
where Customer = tt.Customer
group by Customer
having count(*)>1 ) )
If you just want a query which returns the requested information (so no update):
select distinct CASE WHEN (select count()
from Tab t2
where t2.Customer = t1.Customer or t2.Invoice = t1.Invoice) > 1
THEN 'Product C'
ELSE ProductGroup
END "ProductGroup", Invoice, Customer
from Tab t1

Check if two products belong to same invoice

I have a table of Invoices, InvocicesLines and Products, and I'd like to select all the invoices that have two different products.
How can I do this?
Example:
Invoices table:
InvoiceNo | CustomerId | ...
=============+===============+========+
1 | 1 |
2 | 2 |
3 | 5 |
4 | 7 |
InvoicesLines table:
InvoiceNo (FK) | Id (PK) | ProductId |
===============+===============+============+
1 | 1 | 3 |
2 | 2 | 1 |
2 | 3 | 2 |
4 | 4 | 5 |
I need the invoices which have product 1 and 2:
InvoiceNo |
============+
2 |
You can join twice your invoices with your lines, and return the ones having different products. You must group the result.
select Invoices.IdInvoice
from Inovices
inner join InvoicesLines as First on First.IdInvoice = Invoices.IdInvoice
inner join InvoicesLines as Second on Second.IdInvoice = Invoice.IdInvoice
where First.IdProduct <> Second.IdProduct
group by Invoices.IdInvoice
This is going to return all the invoices with at least two different products.
But if you want to return the invoices with two different products, and only two different products, you can ensure it with a having clausule.
select Invoices.IdInvoice
from Inovices
inner join InvoicesLines as First on First.IdInvoice = Invoices.IdInvoice
inner join InvoicesLines as Second on Second.IdInvoice = Invoice.IdInvoice
where First.IdProduct <> Second.IdProduct
group by Invoices.IdInvoice
having count(Invoices.IdInvoice) = 2
Group by Invoice number and use having clause to return only those invoices which has distinct count of products equal to 2 (or greater of 1, if you want "at least two products"):
select i.InvoiceNumber
from Inoices i
inner join InvoiceLines il on il.InvoiceId = i.InoiceId
group by i.InvoiceNumber
having count(distinct il.ProductId) = 2

Oracle - Count condition case

I am facing a problem with a query. My goal is to get all product names, unit of mass, quantity and number of pallets they are located in. The problem is with number of pallets of item.
QUERY:
SELECT "Product_Name"
, "Unit_of_Mass"
, SUM("Quantity_Per_UOM")
, Count(*) as "Number_Of_Pallet"
FROM
(select p.prod_desc as "Product_Name"
, s.quantity as "Quantity_Per_UOM"
, u.description as "Unit_of_Mass"
, s.container_id
, s.product_id
from wms_stock s
join wms_product p on p.product_id = s.product_id
join wms_uom u on p.uom_base_id = u.uom_id
)
group by "Product_Name", "Unit_of_Mass"
It almost works. The problem is I need to do some condition in Count(*) (that's what I think should be done). In table wms_stock I got product_id and container_id, and when in some row they are same it should count the number of pallets as 1 but still add the quantities.
So from first select:
Product_Name | Quantity | UnitOfMass | ContainerId | ProductId
A | 2 | kg | 10 | 11
A | 1 | kg | 10 | 11
B | 2 | kg | 11 | 12
I should get result
Product_Name | Quantity_Per_UOM | UnitOfMass | Number_Of_Pallet
A | 3 | kg | 1
B | 2 | kg | 1
You can try below condition in your select list -
COUNT(DISTINCT ContainerId || ProductId)
Just for your information, || is not an operator rather it is concatenation operator in Oracle. So i have just concat both the columns and picked up the distinct from them.

SUM in multi-currency

I am trying to do SUM() in a multi-currency setup. The following will demonstrate the problem that I am facing:-
Customer
-------------------------
Id | Name
1 | Mr. A
2 | Mr. B
3 | Mr. C
4 | Mr. D
-------------------------
Item
-------------------------
Id | Name | Cost | Currency
1 | Item 1 | 5 | USD
2 | Item 2 | 2 | EUR
3 | Item 3 | 10 | GBP
4 | Item 4 | 5 | GBP
5 | Item 5 | 50 | AUD
6 | Item 6 | 20 | USD
7 | Item 3 | 10 | EUR
-------------------------
Order
-------------------------
User_Id | Product_Id
1 | 1
2 | 1
1 | 2
3 | 3
1 | 5
1 | 7
1 | 5
2 | 6
3 | 4
4 | 2
-------------------------
Now, I want the output of a SELECT query that lists the Customer Name and the total amount worth of products purchased as:-
Customer Name | Amount
Mr. A | Multiple-currencies
Mr. B | 25 USD
Mr. C | 15 GBP
Mr. D | 2 EUR
So basically, I am looking for a way to add the cost of multiple products under the same customer, if all of them have the same currency, else simply show 'multiple-currencies'. Running the following query will not help:-
SELECT Customer.Name, SUM(Item.Amount) FROM Customer
INNER JOIN Order ON Order.User_Id = Customer.Id
INNER JOIN Item ON Item.Id = Order.Product_Id
GROUP BY Customer.Name
What should my query be? I am using Sqlite
I would suggest two output columns, one for the currency and one for the amount:
SELECT c.Name,
(case when max(currency) = min(currency) then sum(amount)
end) as amount,
(case when max(currency) = min(currency) then max(currency)
else 'Multiple Currencies'
end) as currency
FROM Customer c INNER JOIN
Order o
ON o.User_Id = c.Id INNER JOIN
Item
ON i.Id = o.Product_Id
GROUP BY c.Name
If you want, you can concatenate these into a single string column. I just prefer to have the information in two different columns for something like this.
The above is standard SQL.
I think your query should looks like this
SELECT
Data.Name AS [Customer Name],
CASE WHEN Data.Count > 1 THEN "Multiple-currencies" ELSE CAST(Data.Amount AS NVARCHAR) END AS Amount
FROM
(SELECT
Customer.Name,
COUNT(Item.Currency) AS Count,
SUM(Item.Amount) AS Amount
FROM
Customer
INNER JOIN Order ON Order.User_Id = Customer.Id
INNER JOIN Item ON Item.Id = Order.Product_Id
GROUP BY
Customer.Name) AS Data
A subquery to get the count of currencies and then ask for them in the main query to show the total or the text "Multiple-currencies".
Sorry if there is any mistake or mistype but I don't have a database server to test it
Hope this helps.
IMO I would start by standardizing variable names. Why call ID in customer table USER_ID in order table? Just a pet peeve. Anyway, you should learn how to build queries.
start with joining the customer table to the order table on then join the result to the item table. The first join is on CUSTOMER_ID and the second join is on PRODUCT_ID. Once you have that working use SUM and GROUP BY
Ok, I managed to solve the problem this way:-
SELECT innerQuery.Name AS Name, (CASE WHEN innerQuery.Currencies=1 THEN (innerQuery.Amount || innerQuery.Currency) ELSE 'Mutliple-Currencies' END) AS Amount, FROM
(SELECT Customer.Name, SUM(Item.Amount), COUNT(DISTINCT Item.Currency) AS Currencies, Item.Currency AS Currency FROM Customer
INNER JOIN Order ON Order.User_Id = Customer.Id
INNER JOIN Item ON Item.Id = Order.Product_Id
GROUP BY Customer.Name)innerQuery