This is my table "rating" in my database.
attraction customer rate
------------------------------------
attrac1 cust1 like
attrac2 cust1 dislike
attrac1 cust2 like
What SQL should i write to make the output become like this
attraction like dislike
----------------------------------
attrac1 2 0
attrac2 0 1
I tried this
SELECT a_id,
(SELECT COUNT(rate) FROM rating WHERE rate = 'like') as 'Like',
(SELECT COUNT(rate) FROM rating WHERE rate = 'dislike') as 'Dislike'
FROM rating
But I cant get the result that I want.
SELECT Attraction,
COUNT(CASE WHEN Rate = 'Like' THEN Customer END) [Like],
COUNT(CASE WHEN Rate = 'DisLike' THEN Customer END) [DisLike]
FROM Rating
GROUP BY Attraction
This is one approach:
SELECT a_id,
SUM(Case when rate='like' then 1 else 0 end) as 'Like',
SUM(Case when rate='dislike' then 1 else 0 end) as 'Dislike'
FROM rating
Group BY A_id
Related
I have two database tables customers which contains data about customers with the scheme like that:
mysql> SELECT * FROM customers;
customer_id created_at partner_id
1 "2019-08-20 09:17:58" cats
2 "2019-09-12 11:46:37" dogs
and customers_facts which keeps the customers facts in a form of fact_name and corresponding fact_value.
mysql> SELECT * FROM customers_facts;
customer_id fact_name fact_value
1 name Milton
1 city Milan
1 birthday "2019-08-20 09:17:58"
1 company Idaho
2 surname Bloom
2 name Orlando
3 name Milton
3 city Milan
3 birthday "2011-10-20 11:17:58"
3 company Chicago
I want to create a query to get all customer_id where name=Milton and city=Milan sorted by birthday and company. So in my example the results would be:
mysql> SELECT customer_id FROM ....
customer_id
1
3
I have a query which gets all the customers_id where name=Milton and city=Milan
SELECT cf.* FROM customers_facts cf
WHERE cf.customer_id IN (
SELECT cf.customer_id FROM customers_facts cf
WHERE (cf.fact_name,cf.fact_value) IN (('name','Milton'),('city','Milan'))
GROUP BY cf.customer_id
HAVING COUNT(*) = 2
)
But I have no idea on how to sort the results by fact_value How to do it ? Is it even possible with such scheme ?
This is a little tricky. You can't filter easily before aggregating. So, do the filtering in the having clause:
SELECT customer_id
FROM customers_facts
GROUP BY customer_id
HAVING SUM( fact_name = 'name' AND fact_value = 'Milton' ) > 0 AND
SUM( fact_name = 'city' AND fact_value = 'Milan' ) > 0
ORDER BY MAX(CASE WHEN fact_name = 'birthday' THEN fact_value END) DESC,
MAX(CASE WHEN fact_name = 'company' THEN fact_value END)
Ues pivoting logic to turn out the birthday for each matching customer group:
SELECT customer_id
FROM customers_facts
WHERE (fact_name, fact_value) IN (('name', 'Milton'), ('city', 'Milan'))
GROUP BY customer_id
HAVING MIN(fact_name) <> MAX(fact_name)
ORDER BY MAX(CASE WHEN fact_name = 'birthday' THEN fact_value END);
Other than the ORDER BY clause, I used a HAVING clause which ensures that both the matching name and city were present in each matching customer group.
Edit:
Here is your desired ORDER BY clause:
ORDER BY
MAX(CASE WHEN fact_name = 'birthday' THEN fact_value END) DESC,
MAX(CASE WHEN fact_name = 'company' THEN fact_value END); -- ASC is default
Working with SQL Server 2008 tables where A user can have one or multiple roles
UserDetails:
username level country role
=============================================
john A USA SystemAdmin
john B Brazil Co-ordinator
Smith G Spain Doctor
Anne D USA Nurse
.... ... .... ....
RoleDetails:
role function
============================
SystemAdmin full time
Doctor part time
Co-ordinator consultant
Nurse On call
.... ...
I am trying to create a VIEW where data would look like
username level country SystemAdmin Co-ordinator Doctor Nurse
=============================================================================
john A USA 1 0 0 0
john B Brazil 0 1 0 0
Smith G Spain 0 0 1 0
Anne D USA 0 0 0 1
.... ... .... .... .... .... ...
What I am trying to do is join two tables and generate columns from the rows of the second table where both of them are joined on the basis of UserDetails.role = RoleDetails.role. And most of the columns are varchar in the database. I am trying to generate the Columns from RoleDetails rows with boolean value dynamically. Since RoleDetails table will continue growing, I could not select the individual row like PIVOT ( MAX(role) FOR role IN (Doctor, Nurse...))
Not sure if this is feasible or how to do it. Any direction would be appreciated.
This is a very common question and here is the typical way to do this. If you need to handle the list of roles dynamically then you'll find many solutions out there using dynamic SQL along with XML features to accomplish string concatenation when building the column list.
select
u.username,
min(u.level) as level,
min(u.country) as country,
min(case when role = 'SystemAdmin' then 1 else 0 end) as SystemAdmin,
min(case when role = 'Co-ordinator' then 1 else 0 end) as "Co-ordinator",
min(case when role = 'Doctor' then 1 else 0 end) as Doctor,
min(case when role = 'Nurse' then 1 else 0 end) as Nurse
from UserDetails u left outer join RoleDetails r
on r.role = u.role
group by u.username
Your application may be able to get away with something like this if you can part a hard limit on the number of roles. Depending on how you intend to use this it may be preferable to have static column names anyway.
with NumberedRoles as (
select rolename, row_number() over (order by role) as rn
from RoleDetails
)
select
u.username,
min(u.level) as level,
min(u.country) as country,
min(case when r.rn = 1 then 1 else 0 end) as RoleIsMember01,
min(case when r.rn = 1 then r."role" else null end) as RoleName01,
min(case when r.rn = 1 then 1 else 0 end) as RoleIsMember02,
min(case when r.rn = 1 then r."role" else null end) as RoleName02,
min(case when r.rn = 1 then 1 else 0 end) as RoleIsMember03,
min(case when r.rn = 1 then r."role" else null end) as RoleName03,
...
min(case when r.rn = 1 then 1 else 0 end) as RoleIsMember32,
min(case when r.rn = 1 then r."role" else null end) as RoleName32
from
UserDetails u inner join
NumberedRoles r
on r."role" = u."role"
group by u.username
I have a table with columns pkey and role
I need the o/p table as below
The logic behind the table is if the role is configurator then count of config = 1 and count of review should increased by 1 and count of abstractor increased by 1
Also if the role is reviewer then the count of reviewer should be 1 and count of abstractor should increased by 1.
I have tried the below code but cant derive the o/p.
SELECT
lease_pkey,
SUM(CASE WHEN user_role IN( 'Abstractor') THEN 1 ELSE 0 END) AbstractorChagnes,
SUM(CASE WHEN user_role IN( 'Reviewer') THEN 1 ELSE 0 END) Reviewer,
SUM(CASE WHEN user_role IN( 'Project Owner TL','Configurator') THEN Reviewer = Reviewer+1 ELSE 0 END) AdminChanges
FROM
v_audit_trail_trans
GROUP BY
lease_pkey
Please advice
You have to place the conditions for increasing reviewer and abstractor in their own counters:
SELECT lease_pkey,
SUM(CASE WHEN user_role IN( 'Abstractor','Configurator','Reviewer') THEN 1 ELSE 0 END) AbstractorChagnes,
SUM(CASE WHEN user_role IN( 'Reviewer','Configurator') THEN 1 ELSE 0 END) Reviewer,
...
FROM v_audit_trail_trans
GROUP BY lease_pkey
in table LOG i have the following entries
userid item role
1 Apple Buyer
2 Banana Seller
3 Apple Buyer
1 Banana Seller
3 Orange Buyer
etc
i'm trying to create the following two tables with SQL. table 1:
item countUser1Buy countUser1Sell
Apple
Banana
Orange
AND TAble 2 (here i mean the mean of totals. as in, the mean of the total apples bought
item alluserBuyTotalMean allUserBuyTotalMedian allUserBuyRange allUserBuyStandardDev
Apple
Banana
Orange
i think the first should be a variation on
`SELECT `item`, `role`, count(`item`) as count FROM `LOG` GROUP BY `item`
which is close, giving me
item role count
Apple Buyer 1
Banana Seller 1
but i cant figure out how to make it as i'm trying to get. the second i'm really stumped. thanks
You need conditional aggregation for this:
SELECT `item`,
COUNT(CASE WHEN role='Seller' THEN 1 END) AS countUserSell,
COUNT(CASE WHEN role='Buyer' THEN 1 END) AS countUserBuy
FROM `LOG`
GROUP BY `item`
First query:
SELECT item
, SUM(role = 'Buyer') AS countUser1Buy
, SUM(role = 'Seller') AS countUser1Sell
FROM LOG
WHERE userid = 1
GROUP BY item;
Second query:
SELECT item
, AVG(total) AS alluserBuyTotalMean
, CONCAT(MIN(total), ' - ', MAX(total)) AS allUserBuyRange
, STDDEV_POP(total) AS allUserBuyStandardDev
FROM (
SELECT item
, COUNT(*) AS total
FROM LOG
WHERE role = 'Buyer'
GROUP BY item, userid
) t
GROUP BY item;
SELECT
`item`
,SUM(CASE WHEN `userid`= 1 AND `role` = 'Buyer' THEN 1 ELSE 0 END) as countUser1Buy
,SUM(CASE WHEN `userid` = 1 AND `role` = 'Seller' THEN 1 ELSE 0 END) as countUser1Sell
FROM `LOG`
GROUP BY Item
You will need to make a new CASE statement for each userid, but this should work. Results in the following:
item countUser1Buy countUser1Sell
Apple 1 0
Banana 0 1
Orange 0 0
Objective 1:
Your sales data is stored in the Purchases table.
Your sales staff wants to see the sales data in a pivoted form, broken down by quarter.
If your Purchases table doesn't have sales data, create some. Be sure the data spans four quarters.
Next, write a query to pivot the data as follows:
Album Q1 Q2 Q3 Q4
OK Computer 2 5 3 7
Sea Change 8 6 2 1
Do not create a separate table or a view. Do not alter any tables.
Save your query as dba1lesson10project1.sql and hand in the project.
This is What I need to do. But, the table it wants me to work with looks like this. And it states in the assignment I cannot alter it at all.
CustomerID DateOfPurchase SongID
1 2007-03-31 3
3 2007-06-30 4
4 2007-09-30 4
5 2007-12-31 5
I know I need to join three tables together so I can group by the title. Which are my Songs, Albums, and Purchases tables.
SELECT Albums.Title FROM Albums
LEFT JOIN Songs
INNER JOIN Purchases
ON Songs.SongID = Purchases.SongID
ON Albums.Title = Purchases.SongID,
SELECT Title,
SUM(CASE WHEN QUARTER(DateOfPurchase) = 1 THEN 1 ELSE 0 END) AS 'Q1',
SUM(CASE WHEN QUARTER(DateOfPurchase) = 2 THEN 1 ELSE 0 END) AS 'Q2',
SUM(CASE WHEN QUARTER(DateOfPurchase) = 3 THEN 1 ELSE 0 END) AS 'Q3',
SUM(CASE WHEN QUARTER(DateOfPurchase) = 4 THEN 1 ELSE 0 END) AS 'Q4'
From Purchases
GROUP BY Title;
I'm kind of at a loss here when it comes to Joining three separate tables then pivoting the data
I've tried the code above in multiple other variants which has failed me past the table joining portion.
Any help would be much appreciated.
My suggestion before attempting to PIVOT the data would be to first, write the query to return the columns that you need, this will involve joining your tables. You didn't provide your table definitions so I am making a few guesses on the structure. If your tables are structured similar to the following:
CREATE TABLE Purchases
(`CustomerID` int, `DateOfPurchase` datetime, `SongID` int)
;
CREATE TABLE Albums
(`AlbumId` int, `Title` varchar(11))
;
CREATE TABLE Songs
(`SongID` int, `AlbumID` int)
;
Then you would SELECT from the tables using a JOIN similar to this code:
select a.title,
p.DateOfPurchase
from albums a
inner join songs s
on a.albumid = s.albumId
inner join purchases p
on s.songid = p.songid
This query will return to you the album Title as well as the DateOfPurchase which you need to pivot the data. Once you have the JOINS worked out, then you can replace the p.DateOfPurchase with your aggregate function and CASE expression and add the GROUP BY clause to get the final result:
select a.title,
SUM(CASE WHEN Quarter(p.DateOfPurchase) = 1 THEN 1 ElSE 0 END) AS Q1,
SUM(CASE WHEN Quarter(p.DateOfPurchase) = 2 THEN 1 ELSE 0 END) AS Q2,
SUM(CASE WHEN Quarter(p.DateOfPurchase) = 3 THEN 1 ELSE 0 END) AS Q3,
SUM(CASE WHEN Quarter(p.DateOfPurchase) = 4 THEN 1 ELSE 0 END) AS Q4
from albums a
inner join songs s
on a.albumid = s.albumId
inner join purchases p
on s.songid = p.songid
group by a.title;
See SQL Fiddle with Demo. This gives a result:
| TITLE | Q1 | Q2 | Q3 | Q4 |
| OK Computer | 1 | 0 | 0 | 0 |
| Sea Change | 0 | 1 | 1 | 0 |