Could somebody help with my SQL?
I have a table with records such as:
ID | Car_num | Service | Price
---+---------+---------+------
1 | 001 | shower | 10
2 | 002 | TV | 5
3 | 001 | TV | 5
How to write an SQL query to get the following output?
ID |Car_num | shower | TV
---+--------+--------+---
1 | 001 | 10 | 5
2 | 002 | 0 | 5
Use a pivot query:
SELECT MIN(ID) AS ID,
Car_num,
MAX(CASE WHEN Service = 'shower' THEN Price ELSE 0 END) AS shower,
MAX(CASE WHEN Service = 'TV' THEN Price ELSE 0 END) AS TV
FROM yourTable
GROUP BY Car_num
SELECT ROW_NUMBER() OVER(ORDER BY Car_num) Id,Car_num ,ISNULL([TV],0) [TV],ISNULL([shower],0) [shower]
FROM
(
SELECT Car_num , _Service , ISNULL(Price,0) Price
FROM #Table
)Data
PIVOT
(
MAX(Price) FOR _Service IN ([TV],[shower])
)AS PVT
Try this:
SELECT ID, Car_num
, SUM(IF(Service = 'shower', Price, 0)) AS Shower
, SUM(IF(Service = 'TV', Price, 0)) AS TV
FROM your_table
GROUP BY Car_num;
Related
I've the following query:
SELECT first_period, period, sum(num) trans_num
FROM (SELECT (DATEDIFF(created_at, '2022-12-10') DIV 6) period,
user_id,
count(1) num,
MIN(MIN(DATEDIFF(created_at, '2022-12-10') DIV 6)) OVER (PARTITION BY user_id) as first_period
FROM pos_transactions
WHERE DATE(created_at) >= '2022-12-10'
GROUP BY user_id, DATEDIFF(created_at, '2022-12-10') DIV 6
) u
GROUP BY first_period, period
ORDER BY first_period, period
It returns the following result:
But now I need to make it visualize like a Cohort diagram. So I need to restructure the same result as follows:
+--------------+------+------+------+------+
| first_period | 0 | 1 | 2 | 3 |
+--------------+------+------+------+------+
| 0 | 6230 | 2469 | 2846 | 1713 |
| 1 | | 2589 | 742 | 375 |
| 2 | | | 3034 | 397 |
| 3 | | | | 1207 |
+--------------+------+------+------+------+
Any idea how can I do that?
WITH YOUR_TABLE_DATA(FIRST_PERIOD,PERIOD,TRANS_NUM)AS
(
SELECT 0,0,6230 UNION ALL
SELECT 0,1,2469 UNION ALL
SELECT 0,2,2846 UNION ALL
SELECT 0,3,1713 UNION ALL
SELECT 1,1,2589 UNION ALL
SELECT 1,2,742 UNION ALL
SELECT 1,3,375 UNION ALL
SELECT 2,2,3034 UNION ALL
SELECT 2,3,397 UNION ALL
SELECT 3,3,1207
)
SELECT C.FIRST_PERIOD,
MAX(
CASE
WHEN C.PERIOD=0
THEN C.TRANS_NUM
ELSE 0
END)AS ZERO,
MAX(
CASE
WHEN C.PERIOD=1
THEN C.TRANS_NUM
ELSE 0
END)AS ONE,
MAX(
CASE
WHEN C.PERIOD=2
THEN C.TRANS_NUM
ELSE 0
END)AS TWO,
MAX(
CASE
WHEN C.PERIOD=3
THEN C.TRANS_NUM
ELSE 0
END)AS THREE
FROM YOUR_TABLE_DATA AS C
GROUP BY C.FIRST_PERIOD
After the last update of Mailster (email marketing plugin for wordpress), they have changed the way they store the information about opens, clicks, unsubscribes...
Until now, everything was stored in two databases:
bao_posts: Like any other wordpress post, the information of the
email that is sent was there. (When the post_type = 'newsletter')
bao_mailster_actions: This is where the user's actions with the
email were stored. 1 when it was sent to a person, 2 when they
opened it, 3 when they clicked on it and 4 when they unsubscribed.
And with this query, I could get a table with all the emails and the information of their openings, clicks, unsubscribed...
SELECT bao_posts.post_modified,
bao_posts.ID,
bao_posts.post_title,
COUNT(CASE WHEN bao_mailster_actions.type = 1 then 1 ELSE NULL END) AS Number_People_Reached,
COUNT(CASE WHEN bao_mailster_actions.type = 2 then 1 ELSE NULL END) AS Opens,
COUNT(CASE WHEN bao_mailster_actions.type = 3 then 1 ELSE NULL END) AS Clicks,
COUNT(CASE WHEN bao_mailster_actions.type = 4 then 1 ELSE NULL END) AS Unsubs
FROM bao_posts
LEFT JOIN bao_mailster_actions ON bao_mailster_actions.campaign_id = bao_posts.ID
WHERE bao_posts.post_type = 'newsletter'
GROUP BY bao_posts.ID ;
*Expected result of this query at the end of the post.
Now the problem is that this setting is kept for emails before the update, but it has changed for new ones and now bao_mailster_actions is separated into:
bao_mailster_action_sent
bao_mailster_action_opens
bao_mailster_action_clicks
bao_mailster_action_unsubscribes
I know how to get the count of each of these tables like this:
SELECT bao_mailster_action_sent.campaign_id,
COUNT(bao_mailster_action_sent.count) AS Number_People_Reached
FROM bao_mailster_action_sent
GROUP BY bao_mailster_action_sent.campaign_id;
To get:
campaign_id
Number_People_Reached
9785
300
9786
305
(And so on with each of these 4 new tables).
So what I would like to do would be to join these 4 new queries to the original one. I've been trying to combine different JOINs, but I don't quite understand how to do it.
*Bearing in mind that if an email ID matches in both, I would need it to add up their clicks, opens (or whatever).
The expected outcome would be something like this (the same as the first query but with the aggregate data):
post_modified
ID
post_title
Number_People_Reached
Opens
Clicks
Unsubs
2021-04-29 13:13:03
9785
Prueba email
300
102
30
1
2021-04-30 15:12:01
9786
Segundo email
305
97
56
0
Thanks in advance!
I suggest that you use UNION ALL to join all the tables in a CTE.You can then use this in your query. I have modified the name because we cannot have to records with the same name.
> create table if not exists bao_mailster_action_sent
( campaign_id int,count int);
create table if not exists bao_mailster_action_opens
( campaign_id int,count int);
create table if not exists bao_mailster_action_clicks
( campaign_id int,count int);
create table if not exists bao_mailster_action_unsubscribes
( campaign_id int,count int);
CREATE TABLE if not exists bao_posts(
post_modified date,
ID int,
post_title varchar(50) );
insert into bao_mailster_action_sent values
(1,88),(2,4),(4,6);
insert into bao_mailster_action_opens values
(2,4),(3,5),(4,10);
insert into bao_mailster_action_clicks values
(1,3),(2,3),(4,6);
insert into bao_mailster_action_unsubscribes values
(1,4),(3,5),(4,5);
INSERT INTO bao_posts values
( '2021-03-01',1,'first post'),
( '2021-06-01',2,'second opion'),
( '2021-09-01',3,'third way'),
( '2021-12-01',4,'last post');
WITH bao_mailster_actionsent AS
( SELECT campaign_id,count, 1 type FROM
bao_mailster_action_sent
UNION ALL
SELECT campaign_id,count,2 FROM
bao_mailster_action_opens
UNION ALL
SELECT campaign_id,count,3 FROM
bao_mailster_action_clicks
UNION ALL
SELECT campaign_id,count,4 FROM
bao_mailster_action_unsubscribes)
SELECT bao_mailster_actionsent.campaign_id,
COUNT(bao_mailster_actionsent.count) AS TotalCount,
SUM(bao_mailster_actionsent.count) AS TotalNumber,
'type'
FROM bao_mailster_actionsent
GROUP BY bao_mailster_actionsent.campaign_id,'type' ;
WITH baoMailsterAction AS
( SELECT campaign_id,count, 1 type FROM
bao_mailster_action_sent
UNION ALL
SELECT campaign_id,count,2 FROM
bao_mailster_action_opens
UNION ALL
SELECT campaign_id,count,3 FROM
bao_mailster_action_clicks
UNION ALL
SELECT campaign_id,count,4 FROM
bao_mailster_action_unsubscribes)
SELECT bao_posts.post_modified,
bao_posts.ID,
bao_posts.post_title,
COUNT(CASE WHEN bao_mailster_actions.type = 1 then 1 ELSE NULL END) AS Number_People_Reached,
COUNT(CASE WHEN bao_mailster_actions.type = 2 then 1 ELSE NULL END) AS Opens,
COUNT(CASE WHEN bao_mailster_actions.type = 3 then 1 ELSE NULL END) AS Clicks,
COUNT(CASE WHEN bao_mailster_actions.type = 4 then 1 ELSE NULL END) AS Unsubs
FROM bao_posts
campaign_id | TotalCount | TotalNumber | type
----------: | ---------: | ----------: | ---:
1 | 1 | 88 | 1
2 | 1 | 4 | 1
4 | 1 | 6 | 1
2 | 1 | 4 | 2
3 | 1 | 5 | 2
4 | 1 | 10 | 2
1 | 1 | 3 | 3
2 | 1 | 3 | 3
4 | 1 | 6 | 3
1 | 1 | 4 | 4
3 | 1 | 5 | 4
4 | 1 | 5 | 4
post_modified | ID | post_title | Number_People_Reached | Opens | Clicks | Unsubs
:------------ | -: | :----------- | --------------------: | ----: | -----: | -----:
2021-03-01 | 1 | first post | 1 | 0 | 1 | 1
2021-06-01 | 2 | second opion | 1 | 1 | 1 | 0
2021-09-01 | 3 | third way | 0 | 1 | 0 | 1
2021-12-01 | 4 | last post | 1 | 1 | 1 | 1
db<>fiddle here
I finally got it to work using only the new tables that Mailster created (it seems that finally they did move all the info to the new tables with the update) and with 4 LEFT JOINS.
I leave the code in case someone else finds it useful:
SELECT P.post_modified,
P.ID,
P.post_title,
IFNULL(S.count,0) as 'Total',
IFNULL(O.count,0) as 'Aperturas',
IFNULL(C.count,0) as 'Clicks',
IFNULL(U.count,0) as 'Bajas' from bao_posts as P
LEFT JOIN (select campaign_id, count(DISTINCT subscriber_id) as count from bao_mailster_action_clicks group by campaign_id) as C ON C.campaign_id = P.ID
LEFT JOIN (select campaign_id, count(DISTINCT subscriber_id) as count from bao_mailster_action_opens group by campaign_id) as O ON O.campaign_id = P.ID
LEFT JOIN (select campaign_id, count(DISTINCT subscriber_id) as count from bao_mailster_action_sent group by campaign_id) as S ON S.campaign_id = P.ID
LEFT JOIN (select campaign_id, count(DISTINCT subscriber_id) as count from bao_mailster_action_unsubs group by campaign_id) as U ON U.campaign_id = P.ID
WHERE P.post_type = 'newsletter'
ORDER BY P.post_modified ASC ;
P.S: As I expected, Mailster's support has not helped at all :'(
I have a 6 tables
table countries
country_id | short_name
table user (if status = 2 active if status = 1 inactive)
id | country_id | status
table user_subscribed_disciplines
id | user_id |discipline_id
table disciplin
id | name
table user_subscribed_study_levels
id | user_id | study_level_id
table study_levels
id | name
How to select all countries with his parameters? How to write right sql query?
country | total users count | active users count | inactive users count | discipline subscribers count | top discipline | study level subscribers count | top study level
USA | 506 | 500 | 6 | 50 | PHD | 90 | Social History
CAN | 406 | 406 | 0 | 50 | POS | 0 | Social History
You are looking for a query like below I think:
select c.country_id
, count(u.id) as TotalUsers
, sum(case when u.status = 'active' then 1 else 0 end) as ActiveUsers
, sum(case when u.status = 'Inactive' then 1 else 0 end) as InactiveUsers
, (select count(*) from user_subscribed_disciplines) as DisciplineSubscribers
, (select name from (select top 1 name,count(*) from disciplines group by name order by count(*) desc) t) as TopDiscipline
, (select count*) from user_subscribed_study_levels) as StudyLevelCount
, (select name from (select top 1 name,count(*) from study_levels group by name order by count(*) desc) t) as TopStudyLevel
from countries c
inner join user u on u.country_id=c.country_id
For example we have this ServiceRequests source table in database:
| Id | ClientDepartment | ServiceType | DateTimeServiced |
|----|------------------|-------------|------------------|
| 1 | Sales | Networking | 15.01.17 |
| 2 | Development | Networking | 14.02.17 |
| 3 | Development | Networking | 09.04.17 |
| 4 | Sales | Software | 11.03.17 |
| 5 | Sales | Hardware | 30.03.17 |
| 6 | Development | Hardware | 15.04.17 |
Need to make SQL select query and get result:
|Client\Service| Networking | Software | Hardware | Total |
|--------------|------------|----------|----------|-------|
| Sales | 1 | 1 | 1 | 3 |
| Development | 2 | 0 | 1 | 3 |
Where numbers are count of intersections between ServiceType and ClientDepartment (services per department).
Trying something like this gives very wrong result:
select ClientDepartment,
(select count(t1.ClientDepartment)
from ServiceRequests t1
where t1.ServiceType = 'Networking'
) as Networking,
(select count(t1.ClientDepartment)
from ServiceRequests t1
where t1.ServiceType = 'Software'
) as Software,
(select count(t1.ClientDepartment)
from ServiceRequests t1
where t1.ServiceType = 'Hardware'
) as Hardware,
(select count(t1.ClientDepartment)
from ServiceRequests t1
) as Total
from ServiceRequests
group by ClientDepartment
|Client\Service| Networking | Software | Hardware | Total |
|--------------|------------|----------|----------|-------|
| Sales | 3 | 1 | 2 | 6 |
| Development | 3 | 1 | 2 | 6 |
Hope for help, create example table code
You could use sum on CASE WHEN and group by
in this way you dn't need subselect for each count
select
ClientDepartment
, sum(case when ServiceType = 'Networking' then 1 else 0 end )as Networking
, sum(case when ServiceType = 'Software' then 1 else 0 end ) as Software
, sum(case when ServiceType = 'Hardware' then 1 else 0 end ) as Hardware
, sum(case when ServiceType = 'Networking' then 1 else 0 end ) +
sum(case when ServiceType = 'Software' then 1 else 0 end ) +
sum(case when ServiceType = 'Hardware' then 1 else 0 end ) as Total
from ServiceRequests
group by ClientDepartment
this should work for both the DB ..
We Can Achieve Desired result using Dynamic Sql
IF OBJECT_ID('Tempdb..#Temp') IS NOT NULL
DROP TABLE #Temp
;With cte( Id , ClientDepartment , ServiceType , DateTimeServiced )
AS
(
SELECT 1 , 'Sales' , 'Networking' , '15.01.17' Union all
SELECT 2 , 'Development' , 'Networking' , '14.02.17' Union all
SELECT 3 , 'Development' , 'Networking' , '09.04.17' Union all
SELECT 4 , 'Sales' , 'Software' , '11.03.17' Union all
SELECT 5 , 'Sales' , 'Hardware' , '30.03.17' Union all
SELECT 6 , 'Development' , 'Hardware' , '15.04.17'
)
SELECT ClientDepartment,
ServiceType,
COUNT(ServiceType)OVER(Partition by ClientDepartment,ServiceType Order by Id) AS Cnt INTO #Temp FROM cte --Sample data created here
DECLARE #Column1 nvarchar(max),
#Sql nvarchar(max),
#Column2 nvarchar(max)
SELECT #Column1=STUFF((SELECT DISTINCT ', '+ 'ISNULL('+ServiceType +',''0'') AS '+ServiceType FROM #Temp
FOR XML PATH ('')),1,1,'')
SELECT #Column2=STUFF((SELECT DISTINCT ', '+ +QUOTENAME(ServiceType) FROM #Temp
FOR XML PATH ('')),1,1,'')
SET #Sql='
SELECT *,'+REPLACE(#Column2,',','+')+' AS Total FROM
(
SELECT ClientDepartment AS ''Client\Service'','+#Column1 +' FROM
(
SELECT * FROm #Temp
)AS SRc
PIVOT
(
MAX(Cnt) FOR ServiceType IN ('+#Column2+')
)AS PVT
)DT
Order by 1 desc
'
PRINT #Sql
EXEC(#Sql)
OutPut
Client\Service Hardware Networking Software Total
---------------------------------------------------------
Sales 1 1 1 3
Development 1 2 0 3
There are two tables, recharge and purchase.
select * from recharge;
+-----+------+--------+---------------------+
| idx | user | amount | created |
+-----+------+--------+---------------------+
| 1 | 3 | 10 | 2016-01-09 20:16:18 |
| 2 | 3 | 5 | 2016-01-09 20:16:45 |
+-----+------+--------+---------------------+
select * from purchase;
+-----+------+----------+---------------------+
| idx | user | resource | created |
+-----+------+----------+---------------------+
| 1 | 3 | 2 | 2016-01-09 20:55:30 |
| 2 | 3 | 1 | 2016-01-09 20:55:30 |
+-----+------+----------+---------------------+
I want to figure out balance of users which is SUM(amount) - COUNT(purchase.idx). (in this case, 13)
So I had tried
SELECT (SUM(`amount`)-COUNT(purchase.idx)) AS balance
FROM `recharge`, `purchase`
WHERE purchase.user = 3 AND recharge.user = 3
but, it returned error.
If you want an accurate count, then aggregate before doing arithmetic. For your particular case:
select ((select sum(r.amount) from recharge where r.user = 3) -
(select count(*) from purchase p where p.user = 3)
)
To do this for multiple users, move the subqueries to the from clause or use union all and aggregation. The second is safer if a user might only be in one table:
select user, coalesce(sum(suma), 0) - coalesce(sum(countp), 0)
from ((select user, sum(amount) as suma, null as countp
from recharge
group by user
) union all
(select user, null, count(*)
from purchase
group by user
)
) rp
group by user
It is possible to using union like this
SELECT SUM(`amount`-aidx) AS balance
FROM(
SELECT SUM(`amount`) as amount, 0 as aidx
from `recharge` where recharge.user = 3
union
select 0 as amount, COUNT(purchase.idx) as aidx
from `purchase`
WHERE purchase.user = 3 )a