I have a data of student which has various study and performance improvement. There will be 4 studies and the performance data of the student for each study will be recorded based on 5 days.
Below is the link for the table script and values.
Script Link
I want to categorize the student in such a way that if the performance in any two of the study is worse then it has to be worse, if there is no improvement in any 3 of the studies then it has to be no-improvement else it has to be improvement.
Any help is highly appreciated
select StudentNumber
,case when sum(case when Performance = 'Worsening' then 1 else 0 end) >= 2
then 'Worsening'
else case when sum(case when Performance = 'Improvement' then 1 else 0 end) >= 3
then 'Improvement'
else 'No Improvement'
end
end as Performance
from tbl_student
group by StudentNumber
Related
complete newbie in SQL here. I have an assignment where I was supposed to create a whole bunch of tables and then perform certain filtering among them.
As seen from the picture, these are actually 2 distinct titles (from a larger table that has more of these) but each of them comes as a book, audio and video copy, hence why there are 3 rows for each distinct title.
Is there any way that I can scan through the multiple rows based on the Title and then return just a single row for each Title stating whether it's available as video and audio? So as long as in any 3 rows, the answer is yes in the "available_in_audio" or "available_in_video", that 'yes' will override the 'no' for any columns scanned before or after it.
For example for the 3 Harry Potter and the Chamber of Secrets rows, I just want a single row where "Available_in_Audio" is Yes and "Available_in_Video" is Yes.
If both available_as_video and available_as_audio are "No", means it's a book, if available_as_audio is "Yes" means it's an audio copy and available_as_video means it's a video copy
Thank you so much and sorry for the long question!
Try this
SELECT Title,
CASE WHEN (MAX(CASE WHEN Available_in_Audio = 'Yes' THEN 1 ELSE 0 END)) = 1 THEN 'Yes' ELSE 'No' END) AS Available_in_Audio,
CASE WHEN (MAX(CASE WHEN Available_in_Video = 'Yes' THEN 1 ELSE 0 END)) = 1 THEN 'Yes' ELSE 'No' END) AS Available_in_Video,
FROM <YourTable>
GROUP BY TITLE
I am looking for an efficient alternative to subqueries/joins for this query. Let's say I a table that stores information about companies with the following columns:
name: the name of the company
state: the state the company is located
in
revenue: the annual revenue of the company
employees: how many
employees this company has
active_business: wether or not the company
is in business (1 = yes, 0 = no)
Let's say that from this table, I want to find out how many companies in each state meet the requirement for some minimum amount of revenue, and also how many companies meet the requirement for some minimum number of employees. This can be expressed as the following subquery (can also be written as a a join):
SELECT state,
(
SELECT count(*)
FROM records AS a
WHERE a.state = records.state
AND a.revenue > 1000000
) AS companies_with_min_revenue,
(
SELECT count(*)
FROM records AS a
WHERE a.state = records.state
AND a.employees > 10
) AS companies_with_min_employees
FROM records
WHERE active_business = 1
GROUP BY state
My question is this. Can I do this without the subqueries or joins? Since the query is already iterating over each row (there's no indexes), is there some way I can add a condition that if the row meets the minimum revenue requirements and is in the same state, it will increment some sort of counter for the query (similar to map/reduce)?
I think CASE and SUM will solve it:
SELECT state
, SUM(CASE WHEN R.revenue > 1000000 THEN 1 ELSE 0 END) AS companies_with_min_revenue
, SUM(CASE WHEN R.employees > 10 THEN 1 ELSE 0 END) AS companies_with_min_employees
FROM records R
WHERE R.active_business = 1
GROUP BY R.state
As you can see, we will have a value of 1 per record with a revenue of greater than 1000000 (else 0), then we'll take the sum. The same goes with the other column.
Thanks to this StackOverflow question. You'll find this when you search "sql conditional count" in google.
If I have a table:
matches
id
team_one
team_two
one_score
two_score
How would I make a query giving me the following result:
Team A
Win: 2 Lose: 0 Score: 5
Team B
Win: 2 Lose: 0 Score: 3
Team C
Win: 1 Lose: 1 Score: 3
Team D
Win: 0 Lose: 2 Score: 1
The Team who have won has the higher score in the table.
The trick is that a given team may appear in one of two different columns. You can solve this with a UNION, where the second table for the union simply swaps the columns from the first table. After that it's just a simple GROUP BY:
SELECT team, SUM(Win) As Won, SUM(Loss) as Lost, SUM(score) as Score
FROM
( SELECT team_one as team,
CASE WHEN one_score > two_score THEN 1 ELSE 0 END as Win,
CASE WHEN one_score < two_score THEN 1 ELSE 0 END as Loss, one_score as score
FROM matches
UNION ALL
SELECT team_two as team
CASE WHEN two_score > one_score THEN 1 ELSE 0 END as Win,
CASE WHEN two_score < one_score THEN 1 ELSE 0 END as Loss, two_score as score
FROM matches
) t
GROUP BY team
ORDER By Won, Lost DESC, Score
As an aside, I worked on a database system like this a long time ago, that had a table with paired records. This was not for competition results, but it was paired data. We found it a lot more performant to store two records for each "match". The two records for a match would share a common match_id, but reverse the order in which the "teams" were listed. Front end code and a backend maintenance task were used to guarantee the paired records were stored properly.
This made certain queries we needed to do much more efficient, as we could index the table once and select from the table for specific teams just by looking at its equivalent team_one column. Again, this wasn't sports data, so your results may vary, but we did find for our problem space it worked much better.
Part of what made this efficient in the old system was that, once entered, the paired data rarely changed. This seems like a good fit for what you're doing.
I'm writing a stored procedure that will display yes/no counts by an alcohol category and job number. I started programming the current categories - wine, beer, whisky - via an union all but thinking ahead there might be more categories and I visualize this code getting hefty in size. Is it possible to perform a union all in a loop and then pass the alcohol category argument? Trolled the internet and have seen very little on the subject so any help or guidance will be most appreciated.
The start of my code...
delimiter $$
create procedure alc_cat_yn (in jid int)
begin
select
cast(concat(jobid,' - Wine')
as char(50)) as `Job Number - Consumed Yesterday`
,sum(case when wine_id=1 then 1 else 0 end) as y
,sum(case when wine_id=2 then 1 else 0 end) as n
from demos
where jobid=jid
group by jobid
union all
select
cast(concat(jobid,' - Beer')
as char(50)) as `Job Number - Consumed Yesterday`
,sum(case when beer_id=1 then 1 else 0 end) as y
,sum(case when beer_id=2 then 1 else 0 end) as n
from demos
where jobid=jid
group by jobid
union all
select
cast(concat(jobid,' - Whisky')
as char(50)) as `Job Number - Consumed Yesterday`
,sum(case when whisky_id=1 then 1 else 0 end) as y
,sum(case when whisky_id=2 then 1 else 0 end) as n
from demos
where jobid=jid
group by jobid;
end
In theory, you could have a loop which builds the query string in a loop and executes it as a prepared statement. Doing so, however, is bad practise. Instead, you should avoid having different columns for your different alcohol categories. Use a single column with multiple rows. Each row would contain the jobid, the alcohol category and a value (e.g. 1 or 2).
I'm a bit mystified why your columns are called *_id, as you seem to store some yes/no information, and not an identifier for some row in another table. You might want to choose a less misleading name.
For the category, you could either use an enum, or the name stored in a string, or a number referencing the primary key of some other table that lists your kinds. The enum will mean that every new category requires a change to the database schema. A string might consume considerable amounts of memory, particularly if you choose long names. Therefore, references to another table are the most flexible solution and probably your best choice in the long run.
You could still provide the current structure as a view, based on the extended table. If you use a new name for the restructured table, and reuse the current name for this view, then backwards compatibility with existing code could be maintained.
Little note: MySQL uses 0 or 1 to represent boolean values. So instead of writing case when foo=bar then 1 else 0 end you could simply write foo=bar. This will make your code much shorter. Otoh, it will also make it harder to read at first glance, so perhaps best place a comment somewhere about this use.
I'm having a question that can be explained using a simple fictive table.
Table "Drinks" has just three fields:
Id (1..N) - Primary key
Date ('2012-09-19'...) - Each date can occur very often
Hot (1 for yes, and 0 for false).
I would like to produce a list like this:
Date Total Hot Cold
2012-09-19 14 6 8
2012-09-10 21 18 3
Etc.
The field "Cold" is as you might expect calculated as (Total - Hot).
What I've got so far is:
SELECT Date, count(*) AS Total FROM Drinks GROUP BY Date;
This gives me the desired table, but of course without the columns "Hot" and "Cold".
Is there a way to modify my query so I can produce this table in one go? I can of course built the table in phases using PHP code, but that is probably not the elegant way nor the fastest.
I'm happy to watch and learn... :)
You can add CASE statements in your SELECT clause.
SELECT Date,
count(*) AS Total,
SUM(CASE WHEN Hot = 1 THEN 1 ELSE 0 END) totlHOT,
SUM(CASE WHEN Hot = 0 THEN 1 ELSE 0 END) totalCold
FROM Drinks
GROUP BY Date;
SELECT Date,
count(*) AS Total,
SUM(Hot = 1) Hot,
SUM(Hot = 0) Cold
FROM Drinks
GROUP BY Date;