Mysql to Informix query - mysql

I used following query to retrieve information from a mysql table.
SELECT YEARWEEK(fecha,2) ,CONCAT('Semana ', WEEK(fecha)) as y,count(*) as a
FROM mobile09
WHERE fecha BETWEEN TODAY - 30 AND TODAY GROUP BY 1 ORDER BY 1 ASC
How can I get the same result in a Informix database with same tables?

You're going to have to implement your own week of year function for Informix.
Lucky for you, this has already been done at: IBM Developerworks
CREATE FUNCTION day_one_week_one(yyyy INTEGER)
RETURNING DATE
WITH(NOT VARIANT)
DEFINE jan1 DATE;
LET jan1 = MDY(1, 1, yyyy);
RETURN jan1 + MOD(11 - WEEKDAY(jan1), 7) - 3;
END FUNCTION;
CREATE FUNCTION iso8601_weeknum(dateval DATE DEFAULT TODAY)
RETURNING CHAR(2)
WITH(NOT VARIANT)
DEFINE rv CHAR(8);
DEFINE yyyy CHAR(4);
DEFINE ww CHAR(2);
DEFINE d1w1 DATE;
DEFINE tv DATE;
DEFINE wn INTEGER;
DEFINE yn INTEGER;
-- Calculate year and week number.
LET yn = YEAR(dateval);
LET d1w1 = day_one_week_one(yn);
IF dateval < d1w1 THEN
-- Date is in early January and is in last week of prior year
LET yn = yn - 1;
LET d1w1 = day_one_week_one(yn);
ELSE
LET tv = day_one_week_one(yn + 1);
IF dateval >= tv THEN
-- Date is in late December and is in the first week of next year
LET yn = yn + 1;
LET d1w1 = tv;
END IF;
END IF;
LET wn = TRUNC((dateval - d1w1) / 7) + 1;
-- Calculation complete: yn is year number and wn is week number.
-- Format result.
LET yyyy = yn;
IF wn < 10 THEN
LET ww = "0" || wn;
ELSE
LET ww = wn;
END IF
RETURN ww;
END FUNCTION;
Now you should be able to do
select
year(fecha) || iso8601_weeknum(fecha),
'Semana ' || iso8601_weeknum(fecha) as y,
count(*) as a
from
mobile09
where
fecha between today - 30 and today
group by
1, 2
order by
1 asc;

Related

generating week day by knowing the date in Codesys

very new to Codesys so bear with me.
I know you can use a time picker, but it doesn't get displayed on the web visualisation for some reason. So trying to find a function that will display the day of the week that corresponds to the chosen date.
eg. select 15.10.2018 and get "Monday"
there is a formula for calculating the day of the week on Wikipedia (German).
In CoDeSys:
PROGRAM PLC_PRG
VAR
d : INT:= 15; //day
m : INT:= 10; //month
y: INT:= 2018; //year
w: DINT; //result -> day of the week 1 = monday ...
END_VAR
Implementation:
w:= ((d + TRUNC(2.6 * ((m + 9) MOD 12 + 1) - 0.2) + y MOD 100 +
TRUNC(y MOD 100 / 4) + TRUNC(y / 400) - 2 * TRUNC(y / 100) - 1) MOD 7
+ 7) MOD 7 + 1;
This returns the day of the week as number. 1 is Monday, 2 is Tuesday etc.
It depends on what you have as an input. If you have month, day and year as separate INT values the above example might work. But you can also convert it to DATE which is much better format to work with. That will alow you quickly convert to TIME or TOD and compare dates and do much more.
VAR
DT: DATE;
Str: STRING;
d : INT:= 15; //day
m : INT:= 10; //month
y: INT:= 2018; //year
END_VAR
Str := CONCAT("D#", y);
Str := CONCAT(Str, '-');
Str := CONCAT(Str, m);
Str := CONCAT(Str, '-');
Str := CONCAT(Str, d);
(* Now our string is D#2018-10-15 *)
DT := STRING_TO_DATE(Str);
If you have type DATE, then to calculate day of thr week is very trivial task. All we need to know is what was the day of the week in any given day. Then we can calculate how many days we are from that day, devide by 7 and get MOD.
Here are the facts we have to know
Internal time storage is in seconds from 1 Jan. 1970.
We know that 1 January 1970 was a Thursday.
Ther are 86400 seconds in one day
Here is a function example.
FUNCTION WeekDay : UINT
VAR_INPUT
DT: DATE;
END_VAR
VAR
NumOfDays: DWORD;
END_VAR
(* How many days from 1 Jan. 1970 *)
NumOfDays := DATE_TO_DWORD(DT) / 86400;
WeekDay := DWORD_TO_UINT((NumOfDays + 3) MOD 7);
END_FUNCTION
+3 give us 0 - Monday because in system where 0 is Monday 3 is Thursday and if we want 0 - Sunday we can use +4;
Of course you can optimize function to be only one line
WeekDay := DWORD_TO_UINT(((DATE_TO_DWORD(DT) / 86400) + 3) MOD 7);

What's wrong with this mySQL query? (concat and cast)

The following mySQL query always returns 0 results. The problem began when I added the part that uses the concat and the cast functions. Can you see any syntax error in it?
SELECT p.seccio_id as seccio,
count(distinct r.usuari_upc) as usuaris,
sum(r.preu) as preu
FROM report r, persona p
WHERE r.usuari_upc = p.persona_id
and ((r.any = 2017 and r.mes = 1)
or (r.any > 2017 and r.any < 2018)
or (r.any = 2018 and r.mes = 1)
or (2017 != 2018
and ((r.any = 2017 and r.mes > 1)
or (r.any = 2018 and r.mes < 1))))
and (p.any_id = '2017-2018'
or p.any_id = '2016-2017')
/* The problem is here. */
and ((r.mes < 9
and p.any_id = CONCAT(CAST(r.any - 1 as varchar(4)),"-",CAST(r.any as varchar(4))))
or (r.mes >= 9 and p.any_id = CONCAT(CAST(r.any as varchar(4)),"-",CAST(r.any + 1 as varchar(4)))))
GROUP BY p.seccio_id
ORDER BY p.seccio_id
You can't cast straight from the numeric values to varchar(4) - if you change them all to char(4), you lose the syntax errors.

mysql-function to count days between 2 dates excluding weekends

I've searched through many examples , good ones I got :
Count days between two dates, excluding weekends (MySQL only)
How to count date difference excluding weekend and holidays in MySQL
Calculate diffference between 2 dates in SQL, excluding weekend days
but didn't get most promising solution , so that i can use in my mysql-function for quering lakhs of rows.
This one was very new concept , but didn't worked for inputs like #start_date = '2013-08-03' , #end_date = '2013-08-21' Expected ans : 13 , its giving only 12,
SELECT 5 * (DATEDIFF(#end_date, #start_date) DIV 7) + MID('0123444401233334012222340111123400012345001234550', 7 * WEEKDAY(#start_date) + WEEKDAY(#end_date) + 1, 1);
So i'did tried to make it by myself -
Concept :
Input : 1. period_from_date - from date
2. period_to_date - to date
3. days_to_exclude - mapping : S M T W TH F Sat => 2^0 + 2^6
(sat and sun to exclude) ^ ^ ^ ^ ^ ^ ^
0 1 2 3 4 5 6
DELIMITER $$
USE `db_name`$$
DROP FUNCTION IF EXISTS `FUNC_CALC_TOTAL_WEEKDAYS`$$
CREATE DEFINER=`name`#`%` FUNCTION `FUNC_CALC_TOTAL_WEEKDAYS`( period_from_date DATE, period_to_date DATE, days_to_exclude INT ) RETURNS INT(11)
BEGIN
DECLARE period_total_num_days INT DEFAULT 0;
DECLARE period_total_working_days INT DEFAULT 0;
DECLARE period_extra_days INT DEFAULT 0;
DECLARE period_complete_weeks INT DEFAULT 0;
DECLARE extra_days_start_date DATE DEFAULT '0000-00-00';
DECLARE num_days_to_exclude INT DEFAULT 0;
DECLARE start_counter_frm INT DEFAULT 0;
DECLARE end_counter_to INT DEFAULT 6;
DECLARE temp_var INT DEFAULT 0;
# if no day to exclude return date-diff only
IF days_to_exclude = 0 THEN
RETURN DATEDIFF( period_to_date, period_from_date ) + 1 ;
END IF;
# get total no of days to exclude
WHILE start_counter_frm <= end_counter_to DO
SET temp_var = POW(2,start_counter_frm) ;
IF (temp_var & days_to_exclude) = temp_var THEN
SET num_days_to_exclude = num_days_to_exclude + 1;
END IF;
SET start_counter_frm = start_counter_frm + 1;
END WHILE;
# Get period days count
SET period_total_num_days = DATEDIFF( period_to_date, period_from_date ) + 1 ;
SET period_complete_weeks = FLOOR( period_total_num_days /7 );
SET period_extra_days = period_total_num_days - ( period_complete_weeks * 7 );
SET period_total_working_days = period_complete_weeks * (7 - num_days_to_exclude);
SET extra_days_start_date = DATE_SUB(period_to_date,INTERVAL period_extra_days DAY);
# get total working days from the left days
WHILE period_extra_days > 0 DO
SET temp_var = DAYOFWEEK(period_to_date) -1;
IF POW(2,temp_var) & days_to_exclude != POW(2,temp_var) THEN
SET period_total_working_days = period_total_working_days +1;
END IF;
SET period_to_date = DATE_SUB(period_to_date,INTERVAL 1 DAY);
SET period_extra_days = period_extra_days -1;
END WHILE;
RETURN period_total_working_days;
END$$
DELIMITER ;
Please let me know the holes where this would fail.Open to any suggestions and comments.
UPDATED: If you just need a number of weekdays between two dates you can get it like this
CREATE FUNCTION TOTAL_WEEKDAYS(date1 DATE, date2 DATE)
RETURNS INT
RETURN ABS(DATEDIFF(date2, date1)) + 1
- ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) / 7 * 2
- (DAYOFWEEK(IF(date1 < date2, date1, date2)) = 1)
- (DAYOFWEEK(IF(date1 > date2, date1, date2)) = 7);
Note: The function will still work if you switch start date1 and end date2 dates.
Sample usage:
SELECT TOTAL_WEEKDAYS('2013-08-03', '2013-08-21') weekdays1,
TOTAL_WEEKDAYS('2013-08-21', '2013-08-03') weekdays2;
Output:
| WEEKDAYS1 | WEEKDAYS2 |
-------------------------
| 13 | 13 |
Here is DBFiddle demo
This query will work fine, all the queries above are not working well. Try this :
SELECT ((DATEDIFF(date2, date1)) -
((WEEK(date2) - WEEK(date1)) * 2) -
(case when weekday(date2) = 6 then 1 else 0 end) -
(case when weekday(date1) = 5 then 1 else 0 end)) as DifD
Test it like this :
SELECT ((DATEDIFF('2014-10-25', '2014-10-15')) -
((WEEK('2014-10-25') - WEEK('2014-10-15')) * 2) -
(case when weekday('2014-10-25') = 6 then 1 else 0 end) -
(case when weekday('2014-10-15') = 5 then 1 else 0 end)) as DifD
The result :
DifD
8
I use this. Means there are no functions so can be used in views:
select
datediff(#dateto, #datefrom) +
datediff(#datefrom,
date_add(#datefrom, INTERVAL
floor(datediff(#dateto, #datefrom) / 7) day)) * 2
- case
when weekday(#dateto) = 6 then 2
when weekday(#dateto) = 5 then 1
when weekday(#dateto) < weekday(#datefrom) then 2
else 0
end;
Had a similar issue, I used PHP to remove the weekends, need to know start day and number of days:
EG SQL:
SELECT DAYOFWEEK(`date1`) AS `startday`, TIMESTAMPDIFF(DAY, `date1`, `date2`) AS `interval` FROM `table`
Then run the result through a PHP function:
function noweekends($startday, $interval) {
//Remove weekends from an interval
$wecount = 0; $tmp = $interval;
while($interval/7 > 1) { $interval-=7; $wecount++; }
if($interval+$startday > 5) $wecount++;
$interval = $tmp-($wecount*2);
return $interval;
}
To exclude only Sunday:
CREATE FUNCTION TOTAL_WEEKDAYS(date1 DATE, date2 DATE)
RETURNS INT
RETURN ABS(DATEDIFF(date2, date1)) + 1
- ABS(DATEDIFF(ADDDATE(date2, INTERVAL 1 - DAYOFWEEK(date2) DAY),
ADDDATE(date1, INTERVAL 1 - DAYOFWEEK(date1) DAY))) / 7
- (DAYOFWEEK(IF(date1 < date2, date1, date2)) = 1);
You can also create triggers to automatically calculate it in another column, and you can specify legal holidays in another table:
CREATE OR REPLACE TRIGGER `vacation_before_insert` BEFORE INSERT ON `vacation` FOR EACH ROW
BEGIN
SET #start_date = NEW.Start_date;
SET #end_date = NEW.End_date;
SET #numofholydays = (IFNULL((SELECT SUM(IF(`Date` BETWEEN NEW.Start_date AND NEW.End_date, 1, 0)) as numofdays FROM free_legal_days),0));
SET #totaldays = DATEDIFF(#end_date , #start_date) + 1;
SET #saturdays = WEEK(DATE_ADD(#end_date, INTERVAL 1 DAY))-WEEK(#start_date);
SET #sundays = WEEK(#end_date) - WEEK(#start_date);
SET NEW.Number_of_days = #totaldays-#saturdays-#sundays-#numofholydays;
END;
CREATE OR REPLACE TRIGGER `vacation_before_update` BEFORE UPDATE ON `vacation` FOR EACH ROW
BEGIN
SET #start_date = NEW.Start_date;
SET #end_date = NEW.End_date;
SET #numofholydays = (IFNULL((SELECT SUM(IF(`Date` BETWEEN NEW.Start_date AND NEW.End_date, 1, 0)) as numofdays FROM free_legal_days),0));
SET #totaldays = DATEDIFF(#end_date , #start_date) + 1;
SET #saturdays = WEEK(DATE_ADD(#end_date, INTERVAL 1 DAY))-WEEK(#start_date);
SET #sundays = WEEK(#end_date) - WEEK(#start_date);
SET NEW.Number_of_days = #totaldays-#saturdays-#sundays-#numofholydays;
END;

Add 28 to last 2 digit of date and replace the order

I have a number such as this : 840106
I need to do the following :
Change the number to date add - and flip the number : 06-01-84
add 28 to the last 2 digit that the date will be : 06-01-12
84 + 16 = 00 + 12 = 12
number is always changing sometimes it cab be 850617 , but format is always same add - and add 28 last 2 digit.
any ideas how to help me here ?
Here is a sqlite solution:
create table t( c text);
insert into t (c) values(990831);
insert into t (c) values(840106);
insert into t (c) values(800315);
insert into t (c) values(750527);
insert into t (c) values(700923);
insert into t (c) values(620308);
select c, substr(c,5,2) || '-' || substr(c,3,2) || '-' ||
case when (substr(c,1,2) + 28) < 100 then (substr(c,1,2) + 28)
else case when ((substr(c,1,2) + 28) - 100) < 10 then '0' || ((substr(c,1,2) + 28) - 100)
else ((substr(c,1,2) + 28) - 100)
end
end
from t;
For formatting you can use
http://www.w3schools.com/sql/func_date_format.asp
For adding days to the date you should take a look at date_add() function
mysql> SELECT DATE_ADD('1998-01-02', INTERVAL 31 DAY);
http://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_date-add
Assuming date is the name of the column containing your date:
DATE_FORMAT(DATE_ADD(STR_TO_DATE(date, %y%m%d), INTERVAL 28 YEAR), %d-%m-%y);
What this does is first formats the string into a date, then adds 28 years, then converts back to string with the new format.
SQLite is a lot tricker with this, you'll need to use substrings.
substr(date,5) || "-" || substr(date,3,4) || "-" || CAST(CAST(substr(date,1,2) as integer) + 28 - 100) as text
I'm not too experienced with SQLite so the casting may be a bit weird.
Here is a t-sql solution that you can use and migrate to mysql.
declare #myDate as char(8) = '840106';
declare #y as char(2), #m as char(2), #d as char(2);
set #y = LEFT (#myDate, 2);
declare #yi as int = Convert (int, #y);
IF #y between 30 and 99 ----------- pick a cut-off year
SET #yi = (28 - (100-#yi));
SET #y = CONVERT(char, #yi)
set #m = SUBSTRING(#myDate, 3, 2);
set #d = SUBSTRING(#myDate, 5, 2);
SET #myDate = #d + '-' + #m + '-' + #y;
PRINT #myDate;

How do I find event ranges overlapping a set of hours in MySQL?

Assuming I have table called events with the columns
INT id
DATETIME start_time
DATETIME end_time
how would I find all rows where any part of the time range from start_time to end_time falls within a certain hour range?
For example, I may want to find rows where the events had some portion of them during the 8-10pm hour range.
Something like
select * from events where (hour(start_time) IN (20, 21, 22)) or (hour(end_time) IN (20, 21, 22))
would work, except for events that started before 8pm and ended after 11pm.
Lastly, it has to work across day boundaries, so a range like 23-2 (11pm - 2am) should also work.
Unfortunately I'm unable to modify the schema of the table.
Assuming the start_time and end_time fields are datetime fields, then
SELECT *
FROM events
WHERE (start_time <= $event_end_time) AND (end_time >= $event_start_time)
It's a bit counterintuitive, but if you look at it on a timeline:
A&B are your limit fenceposts. X&Y are the start_time and end_time fields:
A B
p = ----------- event falls outside the boundaries
X Y
A B
q = ----------- partial overlap
X Y
A B
r = ----------- partial overlap again
X Y
A B
s = ----------- full overlap
X Y
A B
t = ----------- outside boundaries
X Y
You're interested in cases Q, R, and S. You'll notice that for those 3 cases, Y is ALWAYS >= A, and X is always <= B
I managed to make this work with the day boundaries requirement. It's ugly, but it seems to cover all the cases.
While you could write a stored procedure to do it, it's easier to express in Java, so:
public void checkEvents (int[][] events, int startHour, int endHour)
final int START = 0;
final int END = 1;
final int HOURS_PER_DAY = 24;
for (int[] event : events) {
int start = startHour;
int end = (endHour < startHour) ? endHour + HOURS_PER_DAY : endHour;
int eventStart = event[START];
int eventEnd = (event[END] < event[START]) ? event[END] + HOURS_PER_DAY : event[END];
if (checkOverlap(result, event, start, end, eventStart, eventEnd))
|| (checkOverlap(result, event, start, end, eventStart + HOURS_PER_DAY, eventEnd + HOURS_PER_DAY))
|| (checkOverlap(result, event, start + HOURS_PER_DAY, end + HOURS_PER_DAY, eventStart, eventEnd))
|| (!checkOverlap(result, event, start + HOURS_PER_DAY, end + HOURS_PER_DAY, eventStart + HOURS_PER_DAY, eventEnd + HOURS_PER_DAY);
System.out.println("overlapped!");
}
}
private boolean checkOverlap(ArrayList<int[]> result, int[] event, int start, int end, int eventStart, int eventEnd) {
if ((eventStart >= start && eventStart < end) || (eventStart < start && eventEnd > start)) {
return true;
}
return false;
}