how to merge together two queries in bigquery - sql

I have 2 queries
Query 1: # of content pieces in a campaign
Select c.campaign_id, sum(case when medium in ('photo', 'story', 'video', 'album') then 1 else 0 end) as totalcontent
From `public_collaboration_contents` as cc
Left join `public_collaborations` as c ON cc.collaboration_id = c.id
Left join `public_influencers` as i on c.influencer_id = i.id
Left join `public_collaboration_tasks` as ct on cc.id = ct.collaboration_content_id
Where cc.state = 'delivered'
And ct.state = 'delivered'
Group by c.campaign_id
Table looks like this:
campaign_id
TotalContent
1233
and
Query 2: campaign name, and Engagement rate
select c.campaign_id, brand_name,pc.title, (sum(psip.likes + psip.comments + psip.video_views)/sum(psip.influencer_starting_followers)) as ER FROM
`production.public_campaigns` as pc
LEFT JOIN `public_sponsored_instagram_posts` as psip
ON pc.id = psip.campaign_id
LEFT JOIN `public_instagram_post_performances` pipp
ON pipp.id=pc.id
LEFT JOIN `public_collaboration_contents`pcc
on pcc.id=pc.id
LEFt JOIN `public_collaborations` as c
ON c.id=pcc.collaboration_id
GROUP BY brand_name, title, campaign_id, pc.id
having (sum(psip.likes + psip.comments + psip.video_views)/sum(psip.influencer_starting_followers)) > 0
Table looks like this:
Campaign_id
Brand_name
title
ER
1233
asdf
asdf
2%
i'm hoping to join them together so my final table can look something like this:
Brand_name
title
ER
TotalContent
asdf
asdf
2%
50
how can i go about this? I tried to do joins with the two queries since they do pull from similar datasets, but i ended up getting the wrong TotalContent value (maybe i did the wrong join? but i tried all the joins and still didn't get the right number)
thank you SO much in advance for the help
EDIT #1:
the query i tried that gave me the wrong count is below (maybe i didn't do the joins right? i'm still very new to sql so could be that...)
select c.campaign_id, brand_name,pc.title, sum(case when medium in ('photo', 'story', 'video', 'album') then 1 else 0 end) as totalcontent, (sum(psip.likes + psip.comments + psip.video_views)/sum(psip.influencer_starting_followers)) as ER FROM
`production.public_campaigns` as pc
LEFT JOIN `public_sponsored_instagram_posts` as psip
ON pc.id = psip.campaign_id
LEFT JOIN `public_instagram_post_performances` pipp
ON pipp.id=pc.id
LEFT JOIN `public_collaboration_contents`pcc
on pcc.id=pc.id
LEFt JOIN `public_collaborations` as c
ON c.id=pcc.collaboration_id
GROUP BY brand_name, title, campaign_id, pc.id
having (sum(psip.likes + psip.comments + psip.video_views)/sum(psip.influencer_starting_followers)) > 0

Related

SQL : Percentage Completed

I need to have a SQL query to calculate the percentage of courses completed by location which are different SQL tables.
Courses table has a Status = 'C' (Completed status).
select Locations.Name, ( ??? ) as PercentCompleted
from Locations inner join Candidates ON Locations.Id = Candidates.SpecifiedLocation
inner join Courses on Candidates.Id = Courses.CandidateId
Group By Locations.Name
I want the results to be:
Location PercentCompleted
Loc1 10
Loc2 50
Loc3 75
where 10, 50 and 75 are percentages of courses completed per location.
Can this be achieved with a single SQL query?
If I understand correctly, I think you can do:
select l.Name,
avg(case when co.status = 'C' then 100.0 else 0 end) as PercentCompleted
from Locations l inner join
Candidates c
on l.Id = c.SpecifiedLocation inner join
Courses co
on c.Id = co.CandidateId
group by l.name;
try like below
select Locations.Name, (sum(case when Status = 'C' then 1 else 0 end)/(select count(*)
from Candidates c where c.SpecifiedLocation=Locations.Id))*100
as PercentCompleted
from Locations inner join Candidates ON Locations.Id = Candidates.SpecifiedLocation
inner join Courses on Candidates.Id = Courses.CandidateId
Group By Locations.Name

SQL count in select query

I have a sql query that creates a label in a cab file for a shopping company. I want to include the amount of packages in an order, some have multiple.
Each returns line in my select query has an I’d and contains a package but I need to count them.
So I have:
Name Email Weight Price ID
Joe B J#.com 10 12.5. 1
Joe B J#.com 10 12.5. 1
Joe C JC#.com 10 14.5. 2
How can I count the ID’s to return a column called pieces and in this example it would be 2 for ID 1 and 1 for ID 2
Thanks
James
enter code here
Select
'WPX' As 'Product Code',
delivery_header.dh_datetime As 'Shipment Date',
'G' As 'Shipment Type',
order_header_detail.ohd_delivery_email As 'Receiver Email Address',
variant_detail.vad_weight As 'Shipment Weight in KG',
(lots of other fields....)
delivery_header.dh_number As 'Shippers Reference',
(SELECT Count(*)
FROM delivery_header
WHERE
dh_number = OU.dh_number
) As 'Number of Pieces',
From delivery_line_item Inner Join
delivery_header On delivery_header.dh_id = delivery_line_item.dli_dh_id
Inner Join
order_line_item On delivery_line_item.dli_oli_id = order_line_item.oli_id
Inner Join
variant_detail On variant_detail.vad_id = order_line_item.oli_vad_id
Inner Join
order_header On order_header.oh_id = order_line_item.oli_oh_id Inner Join
stock_location On stock_location.sl_id = order_line_item.oli_sl_id Inner Join
customer_detail On customer_detail.cd_id = order_header.oh_cd_id Inner Join
order_header_detail On order_header.oh_id = order_header_detail.ohd_oh_id
Left Join
order_header_analysis On order_header.oh_id = order_header_analysis.oha_oh_id
Left Join
order_customer_analysis On order_header.oh_id =
order_customer_analysis.oca_oh_id Left Join
order_delivery_analysis On order_header.oh_id =
order_delivery_analysis.oda_oh_id Left Join
order_line_analysis On order_line_item.oli_id = order_line_analysis.ola_oli_id
Left Join
order_line_product_analysis On order_line_item.oli_id =
order_line_product_analysis.olpa_oli_id Left Join
order_line_variant_analysis On order_line_item.oli_id =
order_line_variant_analysis.olva_oli_id Inner Join
product_detail On product_detail.pd_id = variant_detail.vad_pd_id Inner Join
delivery_method On delivery_method.dm_id = order_header_detail.ohd_dm_id
Inner Join
delivery_method [Delivery Method] On [Delivery Method].dm_id =
order_header_detail.ohd_dm_id Inner Join
currency On currency.c_id = order_header.oh_c_id And currency.c_id =
delivery_method.dm_c_id And currency.c_id = [Delivery Method].dm_c_id
Where
delivery_header.dh_number IN (199364,199363,199362,199360)
Order By delivery_header.dh_number
You can use GROUP BY with COUNT like this:
SELECT ID, COUNT(*) as count FROM tbl GROUP BY ID
What I understood from your question is that, you are looking for output like
Name Email Weight Price ID Pieces
Joe B J#.com 10 12.5. 1 2
Joe B J#.com 10 12.5. 1 2
Joe C JC#.com 10 14.5. 2 1
Using following query you should get the desired output in most of the DBMS.
SELECT NAME,
EMAIL,
WEIGHT,
PRICE,
ID,
(SELECT Count(*)
FROM <YOUR_TABLE_NAME>
WHERE ID= OU.ID) AS Pieces
FROM <YOUR_TABLE_NAME> OU
Similar Query for MS SQL Server can be
SELECT NAME, EMAIL,WEIGHT , Price, ID,CT.Pieces
FROM <YOUR_TABLE_NAME> OU
CROSS APPLY
(
SELECT COUNT(*) AS Pieces FROM <YOUR_TABLE_NAME> IU WHERE OU.ID=IU.ID
)CT

SQL Select Query into another query

I am a beginner with SQL so apologise in advance if my terminology / coding is a little off, or maybe way off.
I have two queries which I would like to join into one. The first creating a list of productids which contain two specific processes.
I then want to use these productids in the second query.
Also is below correct?
group by products.productid having (sum(case when processid like 'pick%' then 1 else 0 end) + sum(case when processid like 'pack%' then 1 else 0 end) = 2)
Any help would be much appreciated, hope this makes sense.
SELECT
Products.ProductID
FROM Products
INNER JOIN Categories ON Products.Category = Categories.Category
INNER JOIN Boms ON Products.Product = Boms.Product AND Boms.BomVersion = Products.BomVersion
LEFT OUTER JOIN Products AS Comp ON Boms.Component = Comp.Product
LEFT OUTER JOIN Processes ON Boms.Process = Processes.Process
WHERE
products.active = 1
and Categorys.Categoryid in ('5','20')
group by products.productid
having (sum(case when processid like 'pick%' then 1 else 0 end) + sum(case when processid like 'pack%' then 1 else 0 end) = 2)
order by products.productid
SELECT
Products.ProductID,
Products.productdescription,
Boms.Type As Type,
Comp.ProductId as Component,
Comp.productdescription,
Boms.Quantity,
BomVersions.BomVersionID,
Processes.processid,
Processes.ProcessDescription
FROM Products
INNER JOIN Categories ON Products.Category = Categories.Category
INNER JOIN Boms ON Products.Product = Boms.Product AND Boms.BomVersion = Products.BomVersion
LEFT OUTER JOIN Products AS Comp ON Boms.Component = Comp.Product
LEFT OUTER JOIN Processes ON Boms.Process = Processes.Process
INNER JOIN BomVersions ON Products.BomVersion = BomVersions.BomVersion
WHERE
products.active = 1
order by products.productid, products.type,comp.productid
To combine them you could do the following.
SELECT b.*
FROM
(SELECT Products.ProductID FROM Products INNER JOIN ...) AS a
INNER JOIN
(SELECT Products.ProductID, Products.productdescription, Boms.Type As Type, ...) AS b
ON a.ProductID = b.ProductID

PostgreSQL value of COUNT multiply by a number

I'm a Rails developer and I'm new to writing SQL script. I have users, portfolios, views, favorites and endorsements tables. users have many portfolios and many endorsements.portfolioshas manyviews, manyfavoritesand manyendorsements`.
Here is the script I wrote
top_users = User.find_by_sql(
"SELECT users.*,
COUNT(portfolios.id) +
COUNT(views.id) +
COUNT(favorites.id) +
COUNT(case when endorsements.portfolio_id = portfolios.id AND portfolios.user_id = users.id then 1 else 0 end) +
COUNT(case when endorsements.user_id = users.id then 1 else 0 end)
AS total
FROM users
LEFT OUTER JOIN portfolios ON portfolios.user_id = users.id
LEFT OUTER JOIN views ON views.subject_id = portfolios.id AND portfolios.user_id = users.id
LEFT OUTER JOIN favorites ON favorites.subject_id = portfolios.id AND portfolios.user_id = users.id
LEFT OUTER JOIN endorsements ON endorsements.portfolio_id = portfolios.id AND portfolios.user_id = users.id OR endorsements.user_id = users.id
GROUP BY users.id
ORDER BY total DESC LIMIT 8"
)
total count is not fully what I expect because each portfolio is worth 50 points, view is 2 points, favorite is worth 10 points, and endorsement is worth 2 points.
Let say we have 3 users
user | COUNT 1 | COUNT 2 | COUNT 3 | COUNT 4 | COUNT 5
-------------------------------------------------------
1 | 0 | 0 | 0 | 0 | 10
2 | 2 | 2 | 2 | 2 | 0
3 | 5 | 0 | 0 | 0 | 0
With my script, the result come in the order of user 1, user 2, then users 3. However base on the points system, it should come out in the order of user 3, user 2 then user 1 because user 3 total points is 250, users 2 total is 128 and user 1 is 20, and this is the order I expect. I did tried this:
top_users = User.find_by_sql(
"SELECT users.*,
COUNT(portfolios.id) * 50 +
COUNT(views.id) * 2 +
COUNT(favorites.id) * 10 +
COUNT(case when endorsements.portfolio_id = portfolios.id AND portfolios.user_id = users.id then 1 else 0 end) * 2 +
COUNT(case when endorsements.user_id = users.id then 1 else 0 end) * 2
AS total
FROM users
LEFT OUTER JOIN portfolios ON portfolios.user_id = users.id
LEFT OUTER JOIN views ON views.subject_id = portfolios.id AND portfolios.user_id = users.id
LEFT OUTER JOIN favorites ON favorites.subject_id = portfolios.id AND portfolios.user_id = users.id
LEFT OUTER JOIN endorsements ON endorsements.portfolio_id = portfolios.id AND portfolios.user_id = users.id OR endorsements.user_id = users.id
GROUP BY users.id
ORDER BY total DESC LIMIT 8"
)
I tried the above script but does not work for me. Any thoughts or help would be much appreciated. Again, I'm very new with raw SQL script.
UPDATED
I ended up doing this to avoid double count issue when LEFT INNTER JOIN multiple table.
SELECT t4.id, t4.username, t4.avatar_url, p_count * 50 + ue_count * 2 + fav_count * 10 + ep_count * 2 + COUNT(vp.id) * 2 as point
FROM (SELECT t3.id, t3.username, t3.avatar_url, p_count, ue_count, fav_count, COUNT(ep.id) as ep_count
FROM( SELECT t2.id, t2.username, t2.avatar_url, p_count, ue_count, COUNT(fav_p.id) as fav_count
FROM (SELECT t1.id, t1.username, t1.avatar_url, p_count, COUNT(e.user_id) as ue_count
FROM (SELECT u.*, COUNT(p.user_id) as p_count
FROM users u
LEFT OUTER JOIN (SELECT user_id, id
FROM portfolios) p
ON u.id = p.user_id
GROUP BY u.id) t1
LEFT OUTER JOIN (SELECT user_id
FROM endorsements) e
ON e.user_id = t1.id
GROUP BY t1.id, t1.username, t1.avatar_url, p_count ) t2
LEFT OUTER JOIN (SELECT p.id, p.user_id
FROM portfolios p
INNER JOIN favorites
ON favorites.subject_id = p.id) fav_p
ON fav_p.user_id = t2.id
GROUP BY t2.id, t2.username, t2.avatar_url, p_count, ue_count) t3
LEFT OUTER JOIN (SELECT p.id, p.user_id
FROM portfolios p
INNER JOIN endorsements
ON endorsements.portfolio_id = p.id) ep
ON ep.user_id = t3.id
GROUP BY t3.id, t3.username, t3.avatar_url, p_count, ue_count, fav_count) t4
LEFT OUTER JOIN (SELECT p.id, p.user_id
FROM portfolios p
INNER JOIN views
ON views.subject_id = p.id) vp
ON vp.user_id = t4.id
GROUP BY t4.id, t4.username, t4.avatar_url, p_count, ue_count, fav_count, ep_count
ORDER BY point DESC
LIMIT 8
Since I'm not familiar with SQL script as I'm a very beginner. The updated code above solve my problem but I wonder how bad the performance would be if I do that. Thanks for any inputs.
After reading through a few more times, I think I got what you were saying. Try this.
SELECT users.id
,COUNT(portfolios.id) * 50 +
COUNT(VIEWS.id) * 2 +
COUNT(favorites.id) * 10 +
COUNT(e1.id) * 2 +
COUNT(e2.id) * 2
AS total
FROM users
LEFT JOIN portfolios
ON portfolios.user_id = users.id
LEFT JOIN VIEWS
ON VIEWS.subject_id = portfolios.id
LEFT JOIN favorites
ON favorites.subject_id = portfolios.id
LEFT JOIN endorsements e1
ON e1.portfolio_id = portfolios.id
LEFT JOIN endorsements e2
ON e2.user_id = users.id
GROUP BY users.id
ORDER BY total DESC LIMIT 8
I assumed that endorsements related to either a user OR a portfolio. I don't know what your values look like in your tables but in theory, since an endorsement relates to a user or a portfolio but a portfolio always relates to a user it wouldn't be strictly necessary to join on both user_id or portfolio_id. In a case like that it's find to join the users table to the endorsements as e1 and the portfolios table to the endorsements as e2 and just add them.
First of all, unless your 'users" table only has one column, this breaks the rule that when you have aggregate functions in your select clause, every column that isn't passed into an aggregate function, has to be in your group by clause.
Second I don't think the case statements inside your COUNT() functions make sense. They are the same statements in your join. You should be able to just count the endoresements.Id and the Portfolios.id, I think. I may be a little fuzzy on what you're looking for. Also, what is a subject_id? is that an id field that determines whether an endorsement belongs to a user or a portfolio?
does a portfolio have both a user_id and a portfolio_id or is it one or the other but not both?
Any time you have multiple outer joins in a GROUP BY query, you have to be careful of double-counting. So I would change COUNT(portfolios.id) to COUNT(DISTINCT portfolios.id) etc. That should also remove the need for your CASE statements. Once you have those counts, you can multiply by their score values, as you say in your question (* 2 or * 50 or whatever you like).

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