I have a table in which I want to store a list of Days chosen (Sun-Sat) But to keep it simple i want to store as ints 1 to 7.
Doing some research I've found 2 ways to handle this "correctly".
creating boolean columns for each day... "Monday" = "False" if not chosen etc.
I really don't like this... too many columns
Another method is to have a table that only holds a composite key
For example day_event
dayID eventID
So if the
event 1 had day 1 2 3
and event 2 had day 2 5 it would be something like this
day : event
1 : 1
2 : 1
2 : 2
3 : 1
5 : 2
then i would be able to select * from day_event where eventID = 2 and so on to get my list of days....
But i really don't like this either... all that just to store a few days?
To me it seems more simple, and practical to have a string column like 'days' like "1,2,3" and "2,5" respectively, as wrong
as it may be.
Is there another solution?
You can store it as a SET column defined as:
CREATE TABLE table_name (
/* ... */
`column_name`SET(
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday'
),
/* ... */
);
A set is like a bitmask so (for example) both Monday and Wednesday could be active simultaneously in the column value.
Sets are limited to a total of 64bits (meaning 64 values) -- which in your case is not a problem.
In your case the SET type is very adequate because you can even filter by this column with very little overhead (compared to the other options the string ad the table this is 0 almost overhead).
SELECT *
FROM `table_name`
WHERE `column_name` = 'Monday,Wednesday'
Related
I have a table that for an ID, will have data in several bucket fields. I want a function to pull out a sum of buckets, but the function parameters will include the start and end bucket field.
So, if I had a table like this:
ID Bucket0 Bucket30 Bucket60 Bucket90 Bucket120
10 5.00 12.00 10.00 0.0 8.00
If I send in the ID and the parameters Bucket0, Bucket0, it would return only the value in the Bucket0 field: 5.00
If I send in the ID and the parameters Bucket30, Bucket120, it would return the sum of the buckets from 30 to 120, or (12+10+0+8) 30.00.
Is there a nicer way to write this other than a huge ugly
if parameter1=bucket0 and parameter2=bucket0
then select bucket0
else if parameter1=bucket0 and parameter2=bucket1
then select bucket0 + bucket1
else if parameter1=bucket0 and parameter2=bucket2
then select bucket0 + bucket1 + bucket2
and so on?
The table already exists, so I don't have a lot of control over that. I can make my parameters for the function however I want. I can safely say that if a set of buckets are wanted, none in the middle will be skipped, so specifying start and end buckets would work. I could have a single comma delimited string of all buckets wanted.
It would have been better if your table had been normalised, like this:
id | bucket | value
---+-----------+------
10 | bucket000 | 5
10 | bucket030 | 12
10 | bucket060 | 10
10 | bucket090 | 0
10 | bucket120 | 8
Also, the buckets should better have names that are easy to compare in ranges, so that bucket030 comes between bucket000 and bucket120 in the normal alphabetical order, which is not the case if you leave out the padded zeroes.
If the above normalisation is not possible, then use an unpivot clause to turn your current table into the structure depicted above:
select id, sum(value)
from (
select *
from mytable
unpivot (value for bucket_id in (bucket0 as 'bucket000',
bucket30 as 'bucket030',
bucket60 as 'bucket060',
bucket90 as 'bucket090',
bucket120 as 'bucket120'))
) normalised
where bucket_id between 'bucket000' and 'bucket060'
group by id
When you do this with parameter variables, make sure those parameters have the padded zeroes as well.
You could for instance ensure that as follows for parameter1:
if parameter1 like 'bucket%' then
parameter1 := 'bucket' || lpad(+substr(parameter1, 7), 3, '0');
end if;
...etc.
I am working on a grading database. My students write a paper and are given a score from 6 to 1 on 7 different fields. A score of 6 is the best with 1 being the worst. The student must get an 80% and no more than one score of a 4 in any one field to pass.
edit: I am going to try and clean this up:
Currently there is one table with the following Fields:
Student_Name
Paper_Analysis (This field can have a value of 1 to 6, 6 being the best)
Paper_Purpose (This field can have a value of 1 to 6, 6 being the best)
Paper_Voice (This field can have a value of 1 to 6, 6 being the best)
Paper_Concision (This field can have a value of 1 to 6, 6 being the best)
Paper_Accuracy (This field can have a value of 1 to 6, 6 being the best)
Paper_Content (This field can have a value of 1 to 6, 6 being the best)
Paper_Reasoning (This field can have a value of 1 to 6, 6 being the best)
Paper_Score (This is a calculated field adding the Paper_Purpose, Paper_Voice, Paper_Concision, Paper_Accuracy, Paper_Content, Paper_Reasoning)
Paper_Average (This field is a percent calculated as [Paper_Score]/42
Paper_Pass (For a student to pass they must have above 80% in the Paper Average field. They are also only allowed one 4 in any of the Paper_Purpose, Paper_Voice, Paper_Concision, Paper_Accuracy, Paper_Content, Paper_Reasoning fields.)
The Paper_Pass field is what I am having trouble with. I used IIf([Paper_Average]>0.8,"PASS","FAIL"), but this does not take in to account the only one 4 rule.
Thanks for the welcome. I am willing to use SQL or whatever works best. The only caveat is I am pretty new to SQL.
Assuming the rule for passing is the following:
To pass, the average score has to be 80% or above and only one score is allowed to be 4 or below.
Then you could use this formula:
IIf(Paper_Average >= 0.8 AND -((Paper_Analysis <= 4) + (Paper_Purpose <= 4) + (Paper_Voice <= 4) + (Paper_Concision <= 4) + (Paper_Accuracy <= 4) + (Paper_Content <= 4) + (Paper_Reasoning <= 4)) <= 1,'PASS','FAIL') AS Paper_Pass
Why does this work?
A boolean value (that is something that can be True or False) has a numeric representation with True being -1 and False being 0. At least in Microsoft Office (which Access is a part of). I use this by summing up the result of each of the seven Paper fields being 4 or less. This is an example for the first two Paper fields:
(Paper_Analysis <= 4) + (Paper_Purpose <= 4)
If Paper_Analysis is 4 or less, then the first summand is -1. If Paper_Purpose is 4 or less as well, then the second summand is also -1, so the result is -2. If Paper_Purpose was, say, a 5, then the second summand would be 0 and the result -1.
If you do this for all 7 Paper fields and negate the result, then the result could be anything between 0 and 7, measuring the number of scores of 4 or below. To pass, this value has to be <= 1.
Apparently, calculated field is way to complex. Could anyone suggest a better way to accomplish what I'm trying to do?
Goal: The value entered in the Strength Field determines that value that appears in the calculated field. Thanks in advance for any help!
[Strength] number field
[StrMod] Calculated field
Below is the expression I tried to build to support the [StrMod] calculated field.
IIf([Strength]=1,-5,
IIf([Strength]>=2 And [Strength]<=3,-4,
IIf([Strength]>=4 And [Strength]<=5,-3,
IIf([Strength]>=6 And [Strength]<=7,-2,
IIf([Strength]>=8 And [Strength]<=9,-1,
IIf([Strength]>=10 And [Strength]<=11,0,
IIf([Strength]>=12 And [Strength]<=13,1,
IIf([Strength]>=14 And [Strength]<=15,2,
IIf([Strength]>=16 And [Strength]<=17,3,
IIf([Strength]>=18 And [Strength]<=19,4,
IIf([Strength]>=20 And [Strength]<=21,5,
IIf([Strength]>=22 And [Strength]<=23,6,
IIf([Strength]>=24 And [Strength]<=25,7,
IIf([Strength]>=26 And [Strength]<=27,8,
IIf([Strength]>=28 And [Strength]<=29,9,
IIf([Strength]=30,10,Null)
Here are a few suggestions all using a non-calculated data field type.
UPDATE QUERY w/ LOOKUP TABLE
Replace the calculated field type to regular number field for [StrMod]. Create a Strength lookup table:
StrengthValue | StrengthCategory
1 -5
2 -4
3 -4
4 -3
5 -3
6 -2
... ...
Then use this table to create the below update query to be run in the AfterUpdate and AfterInsert data macros for main table or same events in main table's form.
UPDATE maintableName INNER JOIN StrengthLookUp
ON maintableName.Strength = StrengthLookup.StrengthValue
SET maintableName.StrMod = StrengthLookUp.StrengthCategory
UPDATE QUERY w/o LOOKUP TABLE
Replace the calculated field type to regular number field for [StrMod] and simply use an update query in AfterUpdate and AfterEvent events:
UPDATE maintableName
SET maintableName.StrMod =
IIf([Strength]=1,-5,
IIf([Strength]>=2 And [Strength]<=3,-4,
IIf([Strength]>=4 And [Strength]<=5,-3,
IIf([Strength]>=6 And [Strength]<=7,-2,
IIf([Strength]>=8 And [Strength]<=9,-1,
IIf([Strength]>=10 And [Strength]<=11,0,
IIf([Strength]>=12 And [Strength]<=13,1,
IIf([Strength]>=14 And [Strength]<=15,2,
IIf([Strength]>=16 And [Strength]<=17,3,
IIf([Strength]>=18 And [Strength]<=19,4,
IIf([Strength]>=20 And [Strength]<=21,5,
IIf([Strength]>=22 And [Strength]<=23,6,
IIf([Strength]>=24 And [Strength]<=25,7,
IIf([Strength]>=26 And [Strength]<=27,8,
IIf([Strength]>=28 And [Strength]<=29,9,
IIf([Strength]=30,10,Null))))))))))))))))
VBA LOGIC
Replace the calculated field type to regular number field for [StrMod]. Then, use the SELECT CASE statement in the main table's form's AfterInsert and AfterUpdate events:
SELECT CASE Me.Strength
Case 1
Me.StrMod = -5
Case 2 To 3
Me.StrMod = -4
Case 4 To 5
Me.StrMod = -3
Case 6 To 7
Me.StrMod = -3
Case 8 To 9
Me.StrMod = -1
Case 10 To 11
Me.StrMod = 0
Case 12 To 13
Me.StrMod = 1
...
END SELECT
Strictly my preference, but I never work with calculated fields in case of database compatibility (i.e., MS Access 2007 accdb users) and upsizing scalability with programming languages (PHP, Python, VB ODBC connections) and other RDMS (SQL Server, MySQL).
I can not check but you will get the idea:
iif(strength/2 >= 15, null, -5 + INT(strength/2))
Did you want to simplify or complicate? If you want just to update your table once then you don't need any lookup tables...
update table
set StrMode = iif(strength/2 >= 15, null, -5 + INT(strength/2))
But if records are added to table from time to time you will need to run update as well.
How to insert data like this in a table in a database? There are two inputboxes on the form. One of them is for WeekId and the other one is for EventId. When I try to insert data to the table, the data are rewritten not exactly what I want. I mean when I insert 1, 15, 26 as eventid for weekid 1, the data is shown like below.
week_id event_id
1 26
The last one is shown but I want to do like below
week_id event_id
1 1
1 15
1 26
1 18
1 15
1 10
How to do it? I use Codeigniter, mysql.
If you're inputting in the input field as an array. I mean, if you input 1,15,26 in eventID inputbox then you should use explode().. example:
$eventID=explode(",",$this->input->post('inputfield'));
$length=sizeof($eventID);
for($i=0;$i<$length;$i++){
//your SQL insert statement here with values $eventID[i] and $weekID
// or your insert function
}
Hope this would help..
I want to query severity/facility from syslog, and translate then from number to meaningful keywords like this:
select case severity
when 0 then 'emerg'
when 1 then 'Alert'
when 2 then 'Crit'
when 3 then 'Error'
when 4 then 'Warn'
when 5 then 'Notice'
when 6 then 'Info'
when 7 then 'Debug'
end,
case facility
when 0 then 'kern'
when 1 then 'user'
...
when 23 then 'local7'
end
from logs.sys_log;
While the range of severity is from 0 to 7, and the range of facility is from 0 to 23.
I will get a very long query string.
Is there any smarter method to create key->value mapping in MySQL, to shorten the query string ?
Create new tables severity_mapping and facility_mapping with two columns:
number
value
And store the data 0-emerg etc. to first table and 0-kern to the second. Later, use JOIN clauses in your query.