MySQL Join, Select, multiple conditions - mysql

I am really stuck at this this multiple condition queries.
There are 2 sets of sample data:
Here's What I want:
I want to know the students that been honorable mentioned by times, ie n=1, n=2, n=3 ... What is their average amount received in 2012 per price, per month, per different type of rewards, and return NULL if there's no value in a particular Month.
So far I have
SELECT Type_Of_Reward, Honorable_Mention, MONTH(date)
FROM Data_2 LEFT JOIN
SELECT(Honorable_Mention, COUNT(*) FROM Data_2 GROUP BY Honorable_Mention ON Student_ID = Honorable_Mention)
WHERE YEAR(Data_1.date)=2012 AND...
Any comments/helps would be greatly appreciated.

You can try this one by using join and using case for all months make sure you have set proper datatype for date column if you are using any server side language i recommend you to make this type of data representation by using server side language for now you can try this
SELECT d.Type_Of_Reward, d2.Honorable_Mention,
(CASE WHEN d2.`Honorable_Mention` IS NOT NULL AND MONTH(d.`date`)=1 THEN d2.`Honorable_Mention` ELSE 0 END) AS jan,
. //for other months
.
.
.
(CASE WHEN d2.`Honorable_Mention_id` IS NOT NULL AND MONTH(d.`date`)=10 THEN d2.`Honorable_Mention` ELSE 0 END) AS `oct`
FROM
`data_1` d LEFT JOIN `data_2` d2 ON(d.`id`=d2 .`Honorable_Mention`)
MONTH

Related

Count consecutive row occurrences

I have a MySQL table with three columns: takenOn (datetime - primary key), sleepDay (date), and type (int). This table contains my sleep data from when I go to bed to when I get up (at a minute interval).
As an example, if I go to bed on Oct 29th at 11:00pm and get up on Oct 30th at 6:00am, I will have 420 records (7 hours * 60 minutes). takenOn will range from 2016-10-29 23:00:00 to 2016-10-30 06:00:00. sleepDay will be 2016-10-30 for all 420 records. type is the "quality" of my sleep (1=asleep, 2=restless, 3=awake). I'm trying to get how many times I was restless/awake, which can be calculated by counting how many times I see type=2 (or type=3) consecutively.
So far, I have to following query, which works for one day only. Is this the correct/"efficient" way of doing this (as this method requires that I have the data without any "gaps" in takenOn)? Also, how can I expand it to calculate for all possible sleepDays?
SELECT
sleepDay,
SUM(CASE WHEN type = 2 THEN 1 ELSE 0 END) AS TimesRestless,
SUM(CASE WHEN type = 3 THEN 1 ELSE 0 END) AS TimesAwake
FROM
(SELECT s1.sleepDay, s1.type
FROM sleep s1
LEFT JOIN sleep s2
ON s2.takenOn = ADDTIME(s1.takenOn, '00:01:00')
WHERE
(s2.type <> s1.type OR s2.takenOn IS NULL)
AND s1.sleepDay = '2016-10-30'
ORDER BY s1.takenOn) a
I have created an SQL Fiddle - http://sqlfiddle.com/#!9/b33b4/3
Thank you!
Your own solution is quite alright, given the assumptions you are aware of.
I present here an alternative solution, that will deal well with gaps in the series, and can be used for more than one day at a time.
The downside is that it relies more heavily on non-standard MySql features (inline use of variables):
select sleepDay,
sum(type = 2) TimesRestless,
sum(type = 3) TimesAwake
from (
select #lagDay as lagDay,
#lagType as lagType,
#lagDay := sleepDay as sleepDay,
#lagType := type as type
from (select * from sleep order by takenOn) s1,
(select #lagDay := '',
#lagType := '') init
) s2
where lagDay <> sleepDay
or lagType <> type
group by sleepDay
To see how it works it can help to select the second select statement on its own. The inner-most select must have the order by clause to make sure the middle query will process the records in that order, which is important for the variable assignments that happen there.
See your updated SQL fiddle.

Using SQL joins to determine when something is available

I have some data about products and services and the dates on which they are and are not available. I want to be able to produce a list of products that are available on any specified date.
The data I have assumes that products are always available by default, but that their availability can be restricted, either by specifying that they are NOT available within certain date ranges, or that they are ONLY available within certain date ranges.
The problem I am having is with the former scenario; I can't find a way to use joins to specify that if a product is within the date range of ANY of its NOT entries, then it should not appear in the results. I can't really find the words to explain this properly, so it is probably best illustrated with a simplified example...
Product table:
ID,Name
0,Apples
1,Bananas
2,Carrots
3,Dates
4,Eggs
Restriction table:
ID,Product_ID,Type,Start,End
0,2,Only,2014-05-20,2014-05-31
1,2,Only,2014-07-01,2014-07-14
2,3,Not,2014-03-05,2014-04-04
3,3,Not,2014-04-29,2014-06-15
Examples of intended results:
Date: 2014-01-01
Products available: Apples, Bananas, Dates, Eggs
Date: 2014-04-04
Products available: Apples, Bananas, Eggs
Date: 2014-05-25
Products available: Apples, Bananas, Carrots, Eggs
Date: 2014-07-02
Products available: Apples, Bananas, Carrots, Dates, Eggs
My current attempt with a left join:
SELECT *
FROM Product LEFT JOIN Restriction ON Product.ID = Restriction.ProductID
WHERE
(
Restriction.Type = 'Only'
AND DATEDIFF(Restriction.Start, '2014-04-04') <= 0
AND DATEDIFF(Restriction.End, '2014-04-04') >= 0
)
OR
(
Restriction.Type = 'Not'
AND
(
DATEDIFF(Restriction.Start, '2014-04-04') > 0
OR
DATEDIFF(Restriction.End, '2014-04-04') < 0
)
)
OR Restriction.Type IS NULL
Output from the above query:
Product.ID,Product.Name,Restriction.Product_ID,Restriction.Type,Restriction.Start,Restriction.End
0,Apples,-,-,-,-,-
1,Bananas,-,-,-,-,-
3,Dates,3,3,Not,2014-04-29,2014-06-15
4,Eggs,-,-,-,-,-
As you can see, "Dates" still appears in the results, because although its join with restriction #2 is omitted, its join with restriction #3 is not. I can't find any way to alter the query to resolve this without breaking the logic in some other way. I do hope that I am making sense here, and that somebody can see whatever piece of insight it is to which I am currently blind.
The database software I'm using is MySQL 5.5.
First get the ones in the restriction table that is not available for now() (you can change that to any date you like)
select *
from restriction
where (type = 'Not' and now() between start and end)
or (type = 'Only' and now() not between start and end);
Now make that part a left outer join and use all rows that get a null from the join
select *
from products p
left outer join (select *
from restriction
where (type = 'Not' and now() between start and end)
or (type = 'Only' and now() not between start and end)) r
on (p.id = r.product_id)
where r.product_id is null;

MySQL: Get the average of a column

I have a table name invoices. There is a column named user and late_fee. I am trying to find out the percentage of late invoices compared to how many invoices total.
He has 16 invoices, which 2 of those invoices are late. I feel like this should be an easy pie query but I can't figure it out for the life of me?
You could use something like this. It gets the count of the late_fee depending on it's value.
select sum( case
when late_fee = 1
then 1
else 0
end
)
/ count(*)
from invoices
group
by user
As #Ravinder pointed out, in MySQL this is also valid (does not work on other platforms though):
select sum( late_fee = 1
)
/ count(*)
from invoices
group
by user

How do I add a column with an auto-incremental name to a MySql table?

I'm using VB.net to write a MYSQL application and one feature I need to add is the ability to add a column for each week that my employees worked. For example I want the first column to be called "W1" and the next one to be "W2" and so on, right up to "W52". so my question is how would I add a column to my table and have it's name add 1 to its current value? if there wasn't any letters in the name it would be easy but I need it to have the "W" in the title as well to avoid confusion. to add the column I have this:
ALTER TABLE manager ADD W1 MEDIUMINT;
i just need the part that adds an INTEGER to a VARCHAR datatype if possible... Maybe there should be some sort of data type conversion involved?
UPDATE:
what i want to display in my vb.net form is a datagrid view that looks exactly like this:
Just to explain further, the black bar at the very top are the date stamps for each week, I would like to have this included in the datagridview if possible but it is not required. Under each week column the employees will be entering the percents they worked (example: 20%, or 0.20 is one day of work) I know this is an odd way of doing things but it's mandatory... and I was wondering if it were possible to automate the creation of these columns rather than me having to manually enter them.
1 possible solution would be to create 2 new tables
tbl_week:
weekid, weekno, start_date, end_date
tbl_weeks_worked:
userid, weekid, worked
and pivot the data in the database. (alternativly you could do this in VB.NET)
if you want the header, you will need to union 2 pivoted queries
e.g:
SELECT '' as userid,
MAX(CASE WHEN w.weekno = 1 THEN w.start_date END)) AS 'W1',
MAX(CASE WHEN w.weekno = 2 THEN w.start_date END)) AS 'W2',
MAX(CASE WHEN w.weekno = 3 THEN w.start_date END)) AS 'W3',
........ etc
FROM tbl_week w
WHERE w.start_date >= start AND w.end_date <= enddate
UNION ALL
SELECT
userid,
SUM(CASE WHEN w.weekno = 1 AND ww.weekid IS NOT NULL THEN worked ELSE 0 END)) AS 'W1',
SUM(CASE WHEN w.weekno = 2 AND ww.weekid IS NOT NULL THEN worked ELSE 0 END)) AS 'W2',
SUM(CASE WHEN w.weekno = 3 AND ww.weekid IS NOT NULL THEN worked ELSE 0 END)) AS 'W3',
........ etc
FROM tbl_week w
LEFT JOIN tbl_weeks_worked ww ON ww.weekid = w.weekid
WHERE w.start_date >= start AND w.end_date <= enddate
GROUP BY userid;
Note: (this will only work for a single year view)

MySQL Query to perform calculation and display data based on 2 different date criteria

Good morning,
I am trying to combine two queries into one so that the result array can be populated into a single table. Data is pulled from a single table, and math calculations must take place for one of the columns. Here is what I have currently:
SELECT
laboratory,
SUM(total_produced_week) AS total_produced_sum,
SUM(total_produced_over14) AS total_over14_sum,
100*(SUM(total_produced_over14)/sum(total_produced_week)) as divided_sum,
max(case when metrics_date =maxdate then total_backlog else null end) as total_backlog,
max(case when metrics_date =maxdate then days_workable else null end) as days_workable,
max(case when metrics_date =maxdate then workable_backlog else null end) as workable_backlog,
max(case when metrics_date =maxdate then deferred_over_30_days else null end) as deferred_over_30_days
FROM
test,
(
select max(metrics_date) as maxdate
from metrics
) as x
WHERE
YEAR(metrics_date) = YEAR(CURDATE())
AND MONTH(metrics_date) = MONTH(CURDATE())
GROUP BY
laboratory
ORDER BY 1 ASC
Here's the breakdown:
For each laboratory site, I need:
1) Perform a MONTH TO DATE (current month only) sum, division and multiply by 100 for each site to obtain percentage.
2) Display other columns (total_backlog, days_workable, workable_backlog, deferred_over_30_days) for the most recent update date (metrics_date) only.
The above query performs #1 just fine - I get a total_produced_sum, total_over14_sum and divided_sum column with correct math.
The other columns mentioned in #2, however, return NULL. Data is available in the table for the most recently updated date, so the columns should be reporting that data. It seems like I have a problem with the CASE, but I'm not very familiar with the function so it could be incorrect.
I am running MySQL 5.0.45
Thanks in advance for any suggestions!
Chris
P.S. Here are the two original queries that work correctly. These need to be combined so that the full resultset can be output to a table, organized by laboratory.
Query 1:
SELECT SUM(total_produced_week) AS total_produced_sum,
SUM(total_produced_over14) AS total_over14_sum
FROM test
WHERE laboratory = 'Site1'
AND YEAR(metrics_date) = YEAR(CURDATE()) AND MONTH(metrics_date) = MONTH(CURDATE())
Query 2:
SELECT laboratory, total_backlog, days_workable, workable_backlog, deferred_over_30_days,
items_over_10_days, open_ncs, total_produced_week, total_produced_over14
FROM metrics
WHERE metrics_date = (select MAX(metrics_date) FROM metrics)
ORDER BY laboratory ASC
Operator Error.
I created a copy of the original table (named "metrics") to a table named "test". I then modified the metrics_date in the new "test" table to include data from January 2011 (for the month-to-date). While the first part of the query that performs the math was using the "test" table (and working properly), the second half that pulls the most-recently-updated data was using the original "metrics" table, which did not have any rows with a metrics_date this month.
When I changed the query to use "test" for both parts of the query, everything works as expected. And now I feel really dumb.
Thanks anyway, guys!