How to separe these values? - mysql

I've been trying to do this around 2 hours and my brain is about to explode.
I have a table called DEPARTMENTS and a column called TOTAL_ROOMS but each DEPARTAMENT have their own room size but I don't know how to show the total rooms of each department.
It should look something like this
DEPARTMENT NAME || TOTAL DEPARTMENTS || TOTAL DEPARTMENTS WITH ONE ROOM || TOTAL DEPARTMENTS WITH TWO ROOMS || TOTAL DEPARTMENTS WITH THREE ROOMS
EXAMPLE A || 10 || 5 || 3 || 2
EXAMPLE B || 8 || 2 || 4 || 2
I Have tried using a WHERE , IN, DISTINCT function but I'm not very professional doing this (I'm still learning) :/ This is what I've done and the column name about rooms size is TOTAL_ROOMS and I'm trying to SUM every ROOM that has "1 room size" then SUM every ROOM that has "2 room size" and shows the result :/
SELECT TOWER.EDI_NAME_TOWER AS "DEPARTMENT NAME",
COUNT(DEPARTAMENT.NRO_DEPARTAMENT) AS "TOTAL DEPARTMENTS"
FROM DEPARTAMENT
JOIN TOWER
ON DEPARTAMENT.ID_TOWER= TOWER.ID_TOWER
GROUP BY TOWER.EDI_NAME_TOWER;

I am not clear what your data looks like so here's a guess where conditional aggregation (sum(case when...)) is used to separate the columns.
drop table if exists t,t1;
create table t (ID_TOWER int,NRO_DEPARTAMENT int);
create table t1(id_tower int, EDI_NAME_TOWER varchar(3));
insert into t values
(1,1),(1,1),(1,1),(1,1),(1,1),(1,2),(1,2),(1,2),(1,3),(1,3),
(2,1),(2,1),(2,1),(2,1),(2,2),(2,2),(2,3),(2,3),(2,3),(2,3);
insert into t1 values
(1,'aaa'),(2,'bbb');
SELECT TOWER.EDI_NAME_TOWER AS "DEPARTMENT NAME",
count(DEPARTAMENT.NRO_DEPARTAMENT) AS "TOTAL DEPARTMENTS",
sum(case when DEPARTAMENT.NRO_DEPARTAMENT = 1 then 1 else 0 end) '1 room',
sum(case when DEPARTAMENT.NRO_DEPARTAMENT = 2 then 1 else 0 end) '2 room',
sum(case when DEPARTAMENT.NRO_DEPARTAMENT = 3 then 1 else 0 end) '3 room'
FROM t DEPARTAMENT
JOIN t1 TOWER
ON DEPARTAMENT.ID_TOWER= TOWER.ID_TOWER
GROUP BY TOWER.EDI_NAME_TOWER;
+-----------------+-------------------+--------+--------+--------+
| DEPARTMENT NAME | TOTAL DEPARTMENTS | 1 room | 2 room | 3 room |
+-----------------+-------------------+--------+--------+--------+
| aaa | 10 | 5 | 3 | 2 |
| bbb | 10 | 4 | 2 | 4 |
+-----------------+-------------------+--------+--------+--------+
2 rows in set (0.00 sec)
If this is not what your data looks like please add sample data as text to the question. If you have more rooms keep adding aggregations, if that becomes unmanageable consider dynamic sql.

Thanks for the answers and sorry for the delay.
#P.Salmon you gave me an idea but i tried and i even failed… This is what i need to show
IMAGE
this is my code
SELECT EDIFICIO.EDI_NOMBRE_EDIFICIO AS "NOMBRE EDIFICIO",
COUNT(DEPARTAMENTO.NRO_DEPARTAMENTO) AS "TOTAL DEPTOS",
SUM(TOTAL_DORMITORIOS) AS "TOTAL DEPTOS 1 DORMITORIO", -- fix
COUNT(TOTAL_DORMITORIOS) AS "TOTAL DEPTOS 2 DORMITORIO", -- fix
COUNT(TOTAL_DORMITORIOS) AS "TOTAL DEPTOS 3 DORMITORIO", -- fix
COUNT(TOTAL_DORMITORIOS) AS "TOTAL DEPTOS 4 DORMITORIO", -- fix
COUNT(TOTAL_DORMITORIOS) AS "TOTAL DEPTOS 5 DORMITORIO" -- fix
FROM DEPARTAMENTO
JOIN EDIFICIO ON DEPARTAMENTO.ID_EDIFICIO= EDIFICIO.ID_EDIFICIO
GROUP BY EDIFICIO.EDI_NOMBRE_EDIFICIO
ORDER BY EDI_NOMBRE_EDIFICIO;
I'm pretty sure it can be done using SUM ! and i was trying this but i don't know how to sum every value and show the result final per department
SELECT ID_EDIFICIO, NRO_DEPARTAMENTO, TOTAL_DORMITORIOS
FROM DEPARTAMENTO
WHERE TOTAL_DORMITORIOS IN (1,2,3,4,5);
EDIT ---- THANKS P.Salmon i just figured out the code
SUM(CASE WHEN TOTAL_DORMITORIOS = '1' THEN 1 ELSE 0 END) AS "TOTAL DEPTOS 1 DORMITORIO",
This sum every room per department!

Related

Refine SQL Query given list of ids

I am trying to improve this query given that it takes a while to run. The difficulty is that the data is coming from one large table and I need to aggregate a few things. First I need to define the ids that I want to get data for. Then I need to aggregate total sales. Then I need to find metrics for some individual sales. This is what the final table should look like:
ID | Product Type | % of Call Sales | % of In Person Sales | Avg Price | Avg Cost | Avg Discount
A | prod 1 | 50 | 25 | 10 | 7 | 1
A | prod 2 | 50 | 75 | 11 | 4 | 2
So % of Call Sales for each product and ID adds up to 100. The column sums to 100, not the row. Likewise for % of In Person Sales. I need to define the IDs separately because I need it to be Region Independent. Someone could make sales in Region A or Region B, but it does not matter. We want aggregate across Regions. By aggregating the subqueries and using a where clause to get the right ids, it should cut down on memory required.
IDs Query
select distinct ids from tableA as t where year>=2021 and team = 'Sales'
This should be a unique list of ids
Aggregate Call Sales and Person Sales
select ids
,sum(case when sale = 'call' then 1 else 0 end) as call_sales
,sum(case when sale = 'person' then 1 else 0 end) as person_sales
from tableA
where
ids in t.ids
group by ids
This will be as follows with the unique ids, but the total sales are from everything in that table, essentially ignoring the where clause from the first query.
ids| call_sales | person_sales
A | 100 | 50
B | 60 | 80
C | 100 | 200
Main Table as shown above
select ids
,prod_type
,cast(sum(case when sale = 'call' then 1 else 0 end)/CAST(call_sales AS DECIMAL(10, 2)) * 100 as DECIMAL(10,2)) as call_sales_percentage
,cast(sum(case when sale = 'person' then 1 else 0 end)/CAST(person_sales AS DECIMAL(10, 2)) * 100 as DECIMAL(10,2)) as person_sales_percentage
,mean(price) as price
,mean(cost) as cost
,mean(discount) as discount
from tableA as A
where
...conditions...
group by
...conditions...
You can combine the first two queries as:
select ids, sum( sale = 'call') as call_sales,
sum(sale = 'person') as person_sales
from tableA
where
ids in t.ids
group by ids
having sum(year >= 2021 and team = 'Sales') > 0;
I'm not exactly sure what the third is doing, but you can use the above as a CTE and just plug it in.

SQL Total of a column but 2 rows multiply each value by a set value

Hello i am trying to get the total of 2 rows by multiplying 1 value by 200 and the other by 50.
I got a table like
=====================
ClubName | Type | Fee
=====================
Club1 |Adult | 1000
Club1 |Child | 500
I am trying to multiply the 1000 by 200 and the 500 by 50 and than add them and that is the total that i am trying to get.
I got the one for adult but how do i than go for child and than plus them?
SELECT Type, SUM(Fee * 200) AS MembershipFee
FROM fees
WHERE Clubname='hillcrest' AND Type='adult'
If I understood you correctly then this should work:
SELECT Type,
SUM(CASE WHEN Type = 'Adult' THEN Fee*200
WHEN Type = 'Child' THEN Fee*50 END) AS MembershipFee
FROM yourTable
WHERE Clubname='hillcrest'
Group BY Type
You can do the following if you just want to get the sum.
SELECT Clubname,
SUM(CASE WHEN Type = 'Adult' THEN Fee*200
WHEN Type = 'Child' THEN Fee*50 END) AS MembershipFee
FROM yourTable
WHERE Clubname='hillcrest'
Group BY Clubname

LEFT JOIN and GROUP BY Issue

Not written MySQL for a very long time and I can't get my head around why this is not working! I have written the following to hopefully allow me to see crop yield per year.
I have two tables, one states how many plants of said variety with the following fields this is called "growseason":
id
username
variety
datestamp
plants
my other table has entries when a user adds a harvest to the database, this is called "harvest" with the following fields:
id
datestamp
username
variety
picked
weight
I am trying to create a table that shows year on year crop per plant, this will give me an indication if the crop is better or worse than the previous year.
SELECT g.Variety,
ROUND(SUM(IF(YEAR(h.datestamp)=YEAR(CURRENT_DATE),h.picked,0)) /
IF(YEAR(g.datestamp)=YEAR(CURRENT_DATE),g.plants,0),0) As FruitPerPlantThisYear,
ROUND(SUM(IF(YEAR(h.datestamp)=YEAR(CURRENT_DATE)-1,h.picked,0)) /
IF(YEAR(g.datestamp)=YEAR(CURRENT_DATE)-1,g.plants,0),0) As FruitPerPlantLastYear
FROM harvest h
LEFT JOIN growseason g ON h.variety = g.variety AND YEAR(h.datestamp) = YEAR(g.datestamp) AND h.username = g.username
WHERE g.username = 'Palendrone' AND picked <> '0'
GROUP BY variety, g.datestamp
Expected output:
Variety | FruitPerPlantThisYear | FruitPerPlantLastYear
-------------------------------------------------------
Var1 | 34 | 31
Var2 | 112 | 123
Var3 | 67 | 41
Actual output:
Variety | FruitPerPlantThisYear | FruitPerPlantLastYear
-------------------------------------------------------
Var1 | 34 |
Var2 | | 123
Var3 | | 41
I understand the g.datestamp in my groupby duplicates the variety names but if I don't add that I am only getting a single instance this year or last year). Having spent hours trying to solve this I am now all out of ideas.
I give in and accept help please! Also not sure how I can structure this any better...
I think you are looking for conditional aggregation and I don't know where you get g.datestamp from or g.plants since they ain't in your table definition.
SELECT g.Variety,
sum(case when YEAR(h.datestamp)=YEAR(CURRENT_DATE) then h.picked else 0 end) /
sum(case when YEAR(g.datestamp)=YEAR(CURRENT_DATE) then g.plants else 0 end) as fruitPerPlantThisYear,
sum(case when YEAR(h.datestamp)=YEAR(CURRENT_DATE) -1 then h.picked else 0 end) /
sum(case when YEAR(g.datestamp)=YEAR(CURRENT_DATE) -1 then g.plants else 0 end) as fruitPerPlantThislastYear
FROM harvest h
LEFT JOIN growseason g ON h.variety = g.variety AND h.username = g.username
WHERE g.username = 'Palendrone' AND picked <> '0'
GROUP BY g.variety

Sum gave me wrong amount

This is my table:
(Stuff Table)
id_stuff | prody_type | semester | amount_prod
1 090 1 10
2 210 2 35
(Amount Table)
id_amount | prod_type | semester | amount_stuff
1 090 1 12
2 210 2 15
(Product Table)
id_prod | type_prod | prod_number
1 090 010
2 210 020
And here's my code from my model file:
$this->db->select("sum(amount_stuff) as 'tot_amount_stuff'")
->from('stuff')
->join('product','prod_type=type_prod')
->join('amount','stuff.prod_type=amount.prod_type')
->WHERE('amount.semester', 2);
Then code to show in my page:
for each.......
<td><?php echo $row->tot_amount_stuf; ?></td>
And in my html page shows: 50 but that's wrong, the correct amount is 15
It's seems the 'sum' taking all from the tables 'Stuff' and 'Amount' on semester 2, but I only need to take/show the sum of amount_stuff from the Amount Table not from both tables.
I'm little bit confused here...Hope anyone can help me.
Best Regards,
Try
SELECT sum(amount_stuff) as 'tot_amount_stuff'
FROM Amount
JOIN Stuff ON (Stuff.prody_type = Amount.prody_type)
JOIN product ON (Amount.prody_type = Product.type_prod)
WHERE amount.semester = 2;
Make sure you're referencing tables and columns in your select
$this->db->select("sum(amount.amount_stuff) as 'tot_amount_stuff'")
->from('stuff')
->join('product','prod_type=type_prod')
->join('amount','stuff.prod_type=amount.prod_type')
->WHERE('amount.semester', 2);
You'll want your SQL to render like so:
SELECT sum(amount.amount_stuff) as 'tot_amount_stuff'
FROM stuff
JOIN product ON (amount.prod_type = product.type_prod)
JOIN amount ON (stuff.prod_type = amount.prod_type)
WHERE amount.semester = '2'
You could also use aliases to shorten this process
SELECT sum(a.amount_stuff) as 'tot_amount_stuff'
FROM stuff s
JOIN product p ON (a.prod_type = p.type_prod)
JOIN amount a ON (s.prod_type = a.prod_type)
WHERE a.semester = '2'

mySQL Query design - calculating a vote score for multiple content items

I have a content items table structured like
| contentid | message | categoryid | userid | dateadded | etc..
15 foo bar 3 4 somedate
16 more foo bar 3 4 somedate
16 foo stuff 3 4 somedate
and a votes table, where direction = 1 = an up vote, and = 2 being a down vote.
| voteid | contentid | userid | direction | dateadded
7 15 4 1 some date
8 15 6 1 some date
9 15 17 2 some date
And I'd like to select a set of content items, having an additional column on the end with its calculated score based on the votes in the votes table.
Previously, I had a 'score' column attached to the content table, and each time a vote was cast, it would update its score. This was done so I wouldnt have to have a more complex query to calculate scores on each SELECT, but I'd like to change this now.
This votes table was designed a while ago, so if changing all the votes values to something other than 1 or 2 (perhaps -1 for a downvote) would make it easier, I will update the entire table.
What would the query be to pull all content items, each with a score in a calculated column?
Assuming the vote "direction" represents up and down votes:
SELECT i.contentid,
SUM(CASE WHEN v.direction = 1 THEN 1
WHEN v.direction = 2 THEN -1
ELSE 0 END) AS Votes
FROM items i
LEFT JOIN votes v
ON i.contentid = v.contentid
GROUP BY i.contentid
HAVING SUM(CASE WHEN v.direction = 1 THEN 1
WHEN v.direction = 2 THEN -1
ELSE 0 END) > -3
SELECT
items.*,
SUM(direction = 1) - SUM(direction = 2) AS score
FROM items
LEFT JOIN votes USING (contentid)
GROUP BY contentid
The reason this works is because a true comparison evaluates to 1 and a false one to 0.