How to pass function a output of select query - sql

I am working on following query
Select p.* from Product Inner Join Product_Category_Maping pcm on P.Id=Pcm.ProductId
where
dbo.[CHECKCHARINDEX](#Keyword,p.Name+' '+
#CatName=(Select C.Name from category C where C.Id=Pcm.CategoryId))=1
I want to pass both product and category name to function for some check . How can I do it

I suggest you to move the select to a join. Makes it easier and clearer.
select p.*
from product p
join product_category_maping pcm
on p.id = pcm.productid
join category c
on c.id = pcm.categoryid
where dbo.[checkcharindex](#keyword, p.name + ' ' + c.name) = 1
Also, I think you forgot to give the product table the alias p.

Related

new to snowflake - issue with SQL statement with joins and pivoting values

I'm trying to model product by have a product table linking to characteristic table with 3 many to many table
eg
Product (productId, brand, description, model)
ProductCharacteristic (productId, characteristicId)
Characteristic (characteristicId, type, name, value)
From this structure I'm trying pivot back into one result to show product fields with and characteristic.type characteristic.value into a select statement.
For example:
select distinct
p.ProductId, p.name, p.description, p.brand, p.model, body, DoorNum
from
Product p
left join
ProductionCharacteristic pc on p.ProductId = pc.ProductId,
(select CharacteristicId, "'Body'" as body, "'DoorNum'" as DoorNum
from Characteristic c
pivot (max(c.name) for c.type IN ('Body' , 'DoorNum'))) temp
where
pc.CharacteristicId = temp.CharacteristicId
Issue1: is any_Value an Aggregate function? it pivot doesnt like it, i'm using max() instead
Issue2: the above select returns 3 rows. is there a way flatten it down to one record?
Notes
I must insist that you NEVER use mixed join expressions. Meaning that if you are going to use the keywords JOIN and LEFT JOIN then don't use , and vice versa.
You didn't make it clear what you expected your output to look like so I am going with a comma separated list, but will also be showing how you can use an array.
I put this in as a comment, but worth repeating: ANY_VALUE() is an aggregate function, but doesn't work inside the context of PIVOT
https://community.snowflake.com/s/question/0D50Z00008uVHTYSA4/anyvalue-does-not-work-on-pivot
Query Options
Option 1 - Inline Pivot (Not recommended as it's harder to read and the pivot sub-query can't be reused)
select
p.ProductId
, p.name
, p.description
, p.brand
, p.model
, listagg(temp.body,', ') as body
, listagg(temp.DoorNum,', ') as doornum1
, arrayagg(temp.DoorNum) as doornum2
from
Product p
left join
ProductionCharacteristic pc
on p.ProductId = pc.ProductId
join (
select CharacteristicId, body, doornum
from Characteristic c
pivot (max(c.name) for c.type IN ('Body' , 'DoorNum')) as p (CharacteristicId, value, body, doornum)
) temp
on pc.CharacteristicId = temp.CharacteristicId
group by 1,2,3,4,5
;
Option 2 - Pivot in CTE (Recommended)
with temp as (
select CharacteristicId, body, doornum
from Characteristic c
pivot (max(c.name) for c.type IN ('Body' , 'DoorNum')) as p (CharacteristicId, value, body, doornum)
)
select
p.ProductId
, p.name
, p.description
, p.brand
, p.model
, listagg(temp.body,', ') as body
, listagg(temp.DoorNum,', ') as doornum1
, arrayagg(temp.DoorNum) as doornum2
from
Product p
left join
ProductionCharacteristic pc
on p.ProductId = pc.ProductId
join temp
on pc.CharacteristicId = temp.CharacteristicId
group by 1,2,3,4,5
;
Option 3 - Lateral Join (Like a correlated subquery)
select
p.ProductId
, p.name
, p.description
, p.brand
, p.model
, temp.body
, temp.doornum1
, temp.doornum2
from
Product p
join lateral (
select listagg(iff(type = 'Body',name,null),', ') as body
,listagg(iff(type = 'DoorNum',name,null),', ') as doornum1
,arrayagg(iff(type = 'DoorNum',name,null)) as doornum2
from Characteristic c
join ProductionCharacteristic pc
on pc.CharacteristicId = c.CharacteristicId
where p.ProductId = pc.ProductId
) temp
;
Hope this helps.

Return rows where a customer bought things on same day

Can someone help me with the rest of my Query.
This query gives me Customer, AdressNr, Date, Employee, Article, ActivityNr
from all the sales in my Company.
SELECT ad.Name + ' ' + ad.Vorname AS Customer,
pa.Kunde AS CustomerNr,
CONVERT(VARCHAR(10),p.datum,126) AS Date,
(SELECT a.name + ' ' + a.Vorname AS Name FROM PRO_Mitarbeiter m LEFT JOIN ADR_Adressen a ON a.AdressNrADR=m.AdressNrADR WHERE m.MitNrPRO = l.MitNrPRO) as Employee,
p.Artikel_1 AS Article,
l.AufgabenNrCRM AS OrderNr
FROM ZUS_Therapie_Positionen p
INNER JOIN CRM_AufgabenLink l ON l.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN CRM_Aufgaben ab ON ab.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN PRO_Auftraege pa ON pa.AuftragNrPRO = ab.AuftragNrPRO
INNER JOIN ADR_Adressen ad ON ad.AdressNrADR = pa.Kunde
INNER JOIN ADR_GruppenLink gl ON gl.AdressNrADR = ad.AdressNrADR
INNER JOIN ADR_Gruppen g ON g.GruppeADR = gl.GruppeADR
WHERE l.MitNrPRO != 0
GROUP BY l.AufgabenNrCRM,ad.Name,ad.Vorname,pa.Kunde,p.datum,p.Artikel_1,l.MitNrPRO
ORDER BY pa.Kunde,p.datum,l.AufgabenNrCRM
My goal is to filter this so i get only rows back where the customer has bought more then 1 Thing on the same day. It doesn't matter if a customer bought the same Article twice on the same day. I want too see this also.
It's to complicated to write some SQL Fiddle for you but in this Picture you can see what my goal is. I want to take away all rows with an X on the left side and thoose with a Circle i want to Keep.
As I don't speak German, I won't target this specifically to your SQL. But see the following quasi-code for a similar example that you should be able to apply to your own script.
SELECT C.CustomerName, O.OrderDate, O.OrderNumber
FROM CUSTOMER C
JOIN ORDERS O ON O.Customer_ID = C.Customer_ID
JOIN
(SELECT Customer_ID, OrderDate
FROM ORDERS
GROUP BY Customer_ID, OrderDate
HAVING COUNT(*) > 1) SRC
ON SRC.Customer_ID = O.Customer_ID AND SRC.OrderDate = O.OrderDate
In the script above, the last query (a subquery) would only return results where a customer had more than one order in a given day. By joining that to your main query, you would effectively produce the result asked in the OP.
Edit 1:
Regarding your comment below, I really recommend just going over your datamodel, trying to understand what's happening here, and fixing it on your own. But there is an easy - albeit hardly optimal solution to this by just using your own script above. Note, while this is not disastrous performance-wise, it's obviously not the cleanest, most effective method either. But it should work:
;WITH CTE AS (SELECT ad.Name + ' ' + ad.Vorname AS Customer,
pa.Kunde AS CustomerNr,
CONVERT(VARCHAR(10),p.datum,126) AS [Date],
(SELECT a.name + ' ' + a.Vorname AS Name FROM PRO_Mitarbeiter m LEFT JOIN ADR_Adressen a ON a.AdressNrADR=m.AdressNrADR WHERE m.MitNrPRO = l.MitNrPRO) as Employee,
p.Artikel_1 AS Article,
l.AufgabenNrCRM AS OrderNr
FROM ZUS_Therapie_Positionen p
INNER JOIN CRM_AufgabenLink l ON l.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN CRM_Aufgaben ab ON ab.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN PRO_Auftraege pa ON pa.AuftragNrPRO = ab.AuftragNrPRO
INNER JOIN ADR_Adressen ad ON ad.AdressNrADR = pa.Kunde
INNER JOIN ADR_GruppenLink gl ON gl.AdressNrADR = ad.AdressNrADR
INNER JOIN ADR_Gruppen g ON g.GruppeADR = gl.GruppeADR
WHERE l.MitNrPRO != 0
GROUP BY l.AufgabenNrCRM,ad.Name,ad.Vorname,pa.Kunde,p.datum,p.Artikel_1,l.MitNrPRO
ORDER BY pa.Kunde,p.datum,l.AufgabenNrCRM)
SELECT C.*
FROM CTE C
JOIN (Select CustomerNr, [Date]
FROM CTE B
GROUP BY CustomerNr, [Date]
HAVING COUNT(*) > 1) SRC
ON SRC.CustomerNr = C.CustomerNr AND SRC.[Date] = C.[Date]
This should work directly. But as I said, this is an ugly workaround where we're basically all but fetching the whole set twice, as opposed to just limiting the sub query to just the bare minimum of necessary tables. Your choice. :)
Tried that also and it didnt work. I also made a new query trying to Keep it so simple as possible and it doesnt work either. It still give me Single values back..
SELECT p.Datum,a.AufgabenNrCRM,auf.Kunde FROM CRM_Aufgaben a
LEFT JOIN ZUS_Therapie_Positionen p ON p.Id_Aktivitaet = a.AufgabenNrCRM
LEFT JOIN PRO_Auftraege auf ON auf.AuftragNrPRO = a.AuftragNrPRO
LEFT JOIN
(SELECT pa.Datum,au.Kunde FROM CRM_Aufgaben aa
LEFT JOIN ZUS_Therapie_Positionen pa ON pa.Id_Aktivitaet = aa.AufgabenNrCRM
LEFT JOIN PRO_Auftraege au ON au.AuftragNrPRO = aa.AuftragNrPRO
GROUP BY pa.Datum,au.Kunde
HAVING COUNT(*) > 1) SRC
ON SRC.Kunde = auf.Kunde
WHERE p.datum IS NOT NULL
GROUP BY p.Datum,a.AufgabenNrCRM,auf.Kunde
ORDER BY auf.Kunde,p.Datum

Sqlite select statement from 2 tables

I have two tables: Products and CategoryProducts.
CategoryProducts contains:
PrdID Category
-----------------
Products contains:
PrdID Barcode Url
-----------------------
I have Product's Barcode value, for example 111111.
Need to select all Products.Url with the same Category, as this item's
Category.
Having Products.PrdID, i can get all needed PrdID's from CategoryProducts like this:
select distinct c1.PrdID
from CategoryProduct_MM c1
where c1.CategoryID in (select c2.CategoryID
from CategoryProduct_MM c2
where c2.PrdID = 175)
Based on your comment, this is what you want:
SELECT t.Url
FROM Products t
INNER JOIN CategoryProducts s
ON(s.PrdID = t.PrdID)
WHERE s.CategoryID = (select p.categoryID from CategoryProducts p
INNER JOIN Products f ON(p.prdID = f.prdID)
WHERE f.barcode = 42244)
Selects all the URLS , that their users are in the same category as PrdID ->175
SELECT
p.url
FROM
Products p
JOIN
CategoryProducts cp ON cp.PrdID = p.id
// WHERE p.id = 175
GROUP BY p.url, p.Category
And if you need add comment query
SELECT p.Url, p.PrdID
FROM Products p
JOIN CategoryProduct cp
ON p.PrdID = cp.PrdID
JOIN
Category c on c.id = cp.CategoryID AND cp.PrdID =175
// you need join table Category
Show me your Category table structure

SQL WHERE Temporary Column

I have this MSSQL Query which works
SELECT c.CategoryName + ' (' + cast(count(ic.CategoryId) as varchar(255)) + ')' AS
CategoryName, count(ic.CategoryId) AS NumPhotos,
c.Slug, c.ParentCategoryId, c.Id
FROM Categories
c LEFT JOIN
ItemCategories ic
on ic.CategoryId = c.Id
GROUP BY c.CategoryName, c.slug, c.ParentCategoryId, c.id
ORDER BY ParentCategoryId DESC
And I want to return only rows, WHERE NumPhotos>0 but temporary columns are not allowed on SQL WHERE clause
The having clause is the canonical solution to your problem. However, I suspect that an inner join would also be appropriate:
SELECT c.CategoryName + ' (' + cast(count(ic.CategoryId) as varchar(255)) + ')' AS CategoryName,
count(ic.CategoryId) AS NumPhotos,
c.Slug, c.ParentCategoryId, c.Id
FROM Categories c INNER JOIN
ItemCategories ic
on ic.CategoryId = c.Id
GROUP BY c.CategoryName, c.slug, c.ParentCategoryId, c.id
ORDER BY ParentCategoryId DESC;
Without sample data, it is hard to be sure, but I'm pretty sure this does the same thing.
The advantage of an inner join is that it might be more efficient, because less (maybe only slightly less) data would be processed and the optimizer has more opportunities to pick the best join algorithm.
Existing comments have given adequate answers, but here is another solution, using a "virtual table":
SELECT * FROM (
SELECT c.CategoryName + ' (' + cast(count(ic.CategoryId) as varchar(255)) + ')' AS
CategoryName, count(ic.CategoryId) AS NumPhotos,
c.Slug, c.ParentCategoryId, c.Id
FROM Categories
c LEFT JOIN
ItemCategories ic
on ic.CategoryId = c.Id
GROUP BY c.CategoryName, c.slug, c.ParentCategoryId, c.id
)
WHERE NumPhotos>0
ORDER BY ParentCategoryId DESC

SQL nested aggregate function as subquery syntax error

I need to perform an average of averages. Figured out how to write the subquery, but the final function throws two errors. Syntax error on line 15 and then on line 1.
The subquery works. I then just need an average of the averages of the products in the same category. What's missing?
SELECT
c."name",
AVG(avgvalue)
FROM
(SELECT
c.name,
p.name,
AVG(a."value") AS avgvalue
FROM
answers a
INNER JOIN
survey_responses sr ON sr.id = a.survey_response_id
AND a.question_id = 13
INNER JOIN
answers category_answer ON category_answer.survey_response_id = sr.id
AND category_answer.question_id = 264
INNER JOIN
answers_categories ac ON category_answer.id = ac.answer_id
INNER JOIN
categories c ON c.id = ac.category_id
INNER JOIN
products p ON p.id = a.product_id
WHERE
c.name IN ('Accounting')
HAVING
count(p.name) > 10) AS ProductAverages
GROUP BY c.NAME
Remove ; after the HAVING clause in the temporary table
HAVING count(p.name)>10