T-SQL - fiscal quarter - sql-server-2008

I want to arrive at an output like 2011-Q4 (Financial Yr-Qtr)
I can do this by:
CASE -- Results: 2011-Q4 (Financial Yr-Qtr)
WHEN MONTH(MyDate) BETWEEN 1 AND 3 THEN concat((YEAR(MyDate) - 1), '-', 'Q4')
WHEN MONTH(MyDate) BETWEEN 4 AND 6 THEN concat((YEAR(MyDate) - 1), '-', 'Q1')
WHEN MONTH(MyDate) BETWEEN 7 AND 9 THEN concat((YEAR(MyDate) - 0), '-', 'Q2')
WHEN MONTH(MyDate) BETWEEN 10 AND 12 THEN concat((YEAR(MyDate) - 0), '-', 'Q3')
END AS FYrQtr
But can the same output be achieved without using CONCAT? (I only have 2008 at work; CONCAT arrived in 2012).
Thanks.

In this particular case you can simply use the + operator plus some cast():
CASE -- Results: 2011-Q4 (Financial Yr-Qtr)
WHEN MONTH(MyDate) BETWEEN 1 AND 3 THEN cast(YEAR(MyDate) - 1 as char(4)) + '-Q4'
WHEN MONTH(MyDate) BETWEEN 4 AND 6 THEN cast(YEAR(MyDate) - 1 as char(4)) + '-Q1'
WHEN MONTH(MyDate) BETWEEN 7 AND 9 THEN cast(YEAR(MyDate) - 0 as char(4)) + '-Q2'
WHEN MONTH(MyDate) BETWEEN 10 AND 12 THEN cast(YEAR(MyDate) - 0 as char(4)) + '-Q3'
END FYrQtr
(but note the use of the cast() function: the concat() does implicit conversion from int to char types, while the + operator requires that the left part and the right part are char types)

Related

Order by for column in varchar type

I have the following column strand which is ordered in ascending order but its taking 3.10 as next after 3.1 instead of 3.2..
the column is varchar type..
Strand
3.1
3.1.1
3.1.1.1
3.1.1.2
3.1.2
3.1.2.1
3.10 # wrong
3.10.1 # wrong
3.10.1.1 # wrong
3.2 <- this should have been after 3.1.2.1
3.2.1
3.2.1.1
..
3.9
3.9.1.1
<- here is where 3.10 , 3.10.1 and 3.10.1.1 should reside
I used the following query to order it;
SELECT * FROM [table1]
ORDER BY RPAD(Strand,4,'.0') ;
how to make sure its ordered in the right way such that 3.10,3.10.1 and 3.10.1.1 is at last
Try this:
DROP TABLE T1;
CREATE TABLE T1 (Strand VARCHAR(20));
INSERT INTO T1 VALUES ('3.1');
INSERT INTO T1 VALUES('3.1.1');
INSERT INTO T1 VALUES('3.1.1.1');
INSERT INTO T1 VALUES('3.1.1.2');
INSERT INTO T1 VALUES('3.2');
INSERT INTO T1 VALUES('3.2.1');
INSERT INTO T1 VALUES('3.10');
INSERT INTO T1 VALUES('3.10.1');
SELECT * FROM T1
ORDER BY STRAND;
SELECT *
FROM T1
ORDER BY
CAST(SUBSTRING_INDEX(CONCAT(Strand+'.0.0.0.0','.',1) AS UNSIGNED INTEGER) *1000 +
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Strand,'.0.0.0.0'),'.',2),'.',-1) AS UNSIGNED INTEGER) *100 +
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Strand,'.0.0.0.0'),'.',3),'.',-1) AS UNSIGNED INTEGER) *10 +
CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(CONCAT(Strand,'.0.0.0.0'),'.',4),'.',-1) AS UNSIGNED INTEGER)
Output not ordeded:
Strand
1 3.1
2 3.1.1
3 3.1.1.1
4 3.1.1.2
5 3.10
6 3.10.1
7 3.2
8 3.2.1
Output Ordered:
Strand
1 3.1
2 3.1.1
3 3.1.1.1
4 3.1.1.2
5 3.2
6 3.2.1
7 3.10
8 3.10.1
you can order the result baset on the integer value of your field. your code will looks like
select [myfield]from [mytable] order by
convert(RPAD(replace([myfield],'.',''),4,0),UNSIGNED INTEGER);
in this code replace function will cleand the dots (.)
hope thin help
You must normalize each group of digits
SELECT * FROM [table1]
ORDER BY CONCAT(
LPAD(SUBSTRING_INDEX(Strand,'.',1),3,'0'), '-',
LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(Strand,'.',2),'.',-1),3,'0'), '-',
LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(Strand,'.',3),'.',-1),3,'0'), '-',
LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX(Strand,'.',3),'.',-1),3,'0'));
sample
mysql> SELECT CONCAT(
-> LPAD(SUBSTRING_INDEX('3.10.1.1','.',1),3,'0'), '-',
-> LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX('3.10.1.1','.',2),'.',-1),3,'0'), '-',
-> LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX('3.10.1.1','.',3),'.',-1),3,'0'), '-',
-> LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX('3.10.1.1','.',3),'.',-1),3,'0'));
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| CONCAT(
LPAD(SUBSTRING_INDEX('3.10.1.1','.',1),3,'0'), '-',
LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX('3.10.1.1','.',2),'.',-1),3,'0'), '-',
LPAD(SUBSTRING_INDEX(SUBSTRING_INDEX('3.10.1.1','.',3),'.',-1),3,'0'), '-',
LPAD(SUBSTRING_INDEX(SUBSTRI |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 003-010-001-001 |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0,00 sec)
Cause "strand" column is text data, so it will be ordered in alphabetical. To make it be ordered as your desire, you should format your data before insert or update it. Suppose maximum digit for each level is 3, your data should be formated like this
003.001
003.001.001
003.001.001.001
003.002
003.002.001
003.002.001.001
003.010
010.001
The altenative way is splitting "strand" column into mutiple columns. Each column will store data for each level, such as
Level1 | Level2 | Level3 ...
3 | 1 | 0
3 | 1 | 1
3 | 2 | 0
...
3 | 10 | 0
Datatype of these columns should be number and then you should be able to order by these columns.
If the point(.) in your data is no more than 3, you can try this:
select *
from demo
order by replace(Strand, '.', '') * pow(10, (3 + length(replace(Strand, '.', '')) - length(Strand)))
If the point is uncertain, here you can should use subquery to get max num of point:
select demo.Strand
from demo
cross join (
select max(length(Strand) - length(replace(Strand, '.', ''))) as num from demo
) t
order by replace(Strand, '.', '') * pow(10, (num + length(replace(Strand, '.', '')) - length(Strand)))
See demo in Rextester.
As you see, I've used function replace, length, pow in order by clause.
1) replace(Strand, '.', '') will give us int number, like:
replace('3.10.1.1', '.', '') => 31011;
2) (3 + length(replace(Strand, '.', '')) - length(Strand)) will give us the count of point which the max num of point minus point's count in Strand, like:
3.1 => 2;
3)pow returns the value of X raised to the power of Y;
so the sample data will be calculated like:
3100
3110
3111
3112
3120
3121
31000
31010
31011
3200
3210
3211
3900
3911
by these nums, you will get the right sort.

Compare the digits of two integers in each decimal position

I am not sure I am describing the problem using the correct terms, my math English is not that good.
What I need to do is check if they match for each digit of two integers based on the position of the digit: ones, tens, .. etc
For example check the following table of different numbers and the wanted comparison result:
number1 | number2 | desired result
-----------------------------------
100 | 101 | 001
443 | 143 | 300
7001 | 8000 | 1001
6001 | 8000 | 2001
19 | 09 | 10
Basically I need the absolute value of subtraction for each digit alone. So for the first example:
1 0 0
1 0 1 -
--------
0 0 1
And second:
4 4 3
1 4 3 -
-------
3 0 0
And third:
7 0 0 1
8 0 0 0 -
---------
1 0 0 1
This needs to be done in mysql. Any ideas please?
This should do the job if your numbers are below 10000.
If they exceed, simply modify the query ;)
SELECT number1,
number2,
REVERSE(CONCAT(ABS(SUBSTRING(REVERSE(number1), 1, 1) - SUBSTRING(REVERSE(number2), 1, 1)),
IF(CHAR_LENGTH(number1) > 1, ABS(SUBSTRING(REVERSE(number1), 2, 1) - SUBSTRING(REVERSE(number2), 2, 1)), ''),
IF(CHAR_LENGTH(number1) > 2, ABS(SUBSTRING(REVERSE(number1), 3, 1) - SUBSTRING(REVERSE(number2), 3, 1)), ''),
IF(CHAR_LENGTH(number1) > 3, ABS(SUBSTRING(REVERSE(number1), 4, 1) - SUBSTRING(REVERSE(number2), 4, 1)), ''))) as `desired result`
FROM numbers
for 3 digit numbers:
SELECT number1,
number2,
CONCAT(
ABS(SUBSTRING(number1, 1, 1) - SUBSTRING(number2, 1,1)),
ABS(SUBSTRING(number1, 2, 1) - SUBSTRING(number2, 2,1)),
ABS(SUBSTRING(number1, 3, 1) - SUBSTRING(number2, 3,1))
)
FROM numbers
actually you don't have reverse the string at all. this comes from a more mathematical approach I tried before ;)
if you want to do it with integers only, it can be done this way (for 5 digits as an example):
select abs(number1/10000 - number2/10000) * 10000 +
abs(number1/1000 % 10 - number2/100 % 10) * 1000 +
abs(number1/100 % 10 - number2/100 % 10) * 100 +
abs(number1/10 % 10 - number2/10 % 10) * 10 +
abs(number1 % 10 - number2 % 10)

Error Code: 1582 Incorrect parameter count in the call to native function 'STR_TO_DATE'

i hava a query on mysql, and i like to get the date value.
here's the sql
SELECT DISTINCT pegawai.NIP_BARU, pegawai.NAMA_PEGAWAI, pegawai.KODE_PANGKAT_TERAKHIR,pangkat_golongan.NAMA_PANGKAT, pangkat_golongan.GOLONGAN, pegawai.MASA_KERJA_THN_AKHIR, gaji.MASA_KERJA_GOLONGAN, gaji.NOMINAL_GAJI,CASE PEGAWAI.TMT_GOL
WHEN (pangkat_golongan.JENIS_GOLONGAN = '2') AND pegawai.MASA_KERJA_THN_AKHIR MOD 2 = 0 AND 12 - pegawai.MASA_KERJA_BLN_AKHIR + MONTH(pegawai.TMT_GOL)> 12 THEN 2 + YEAR(pegawai.TMT_GOL)
WHEN (pangkat_golongan.JENIS_GOLONGAN = '1') AND pegawai.MASA_KERJA_THN_AKHIR MOD 2 = 1 AND 12 - pegawai.MASA_KERJA_BLN_AKHIR + MONTH(pegawai.TMT_GOL)> 12 THEN 2 + YEAR(pegawai.TMT_GOL)
WHEN (pangkat_golongan.JENIS_GOLONGAN = '1') AND pegawai.MASA_KERJA_THN_AKHIR MOD 2 = 0 AND 12 - pegawai.MASA_KERJA_BLN_AKHIR + MONTH(pegawai.TMT_GOL)< 12 THEN YEAR(pegawai.TMT_GOL)
WHEN (pangkat_golongan.JENIS_GOLONGAN = '2') AND pegawai.MASA_KERJA_THN_AKHIR MOD 2 = 1 AND 12 - pegawai.MASA_KERJA_BLN_AKHIR + MONTH(pegawai.TMT_GOL)< 12 THEN YEAR(pegawai.TMT_GOL)
ELSE 1 + YEAR(pegawai.TMT_GOL) END AS TAHUN_HITUNG,CASE PEGAWAI.MASA_KERJA_BLN_AKHIR
WHEN (12 -(pegawai.MASA_KERJA_BLN_AKHIR) + MONTH(pegawai.TMT_GOL) > 12)
THEN (12 - (pegawai.MASA_KERJA_BLN_AKHIR) + MONTH(pegawai.TMT_GOL) - 12)
ELSE (12 - (pegawai.MASA_KERJA_BLN_AKHIR) + MONTH(pegawai.TMT_GOL)) END AS BULAN_HITUNG, STR_TO_DATE(TAHUN_HITUNG, BULAN_HITUNG, '01','%Y-%m-%d') AS TMT_HITUNG FROM pegawai, gaji, pangkat_golongan WHERE gaji.KODE_GOLONGAN = pegawai.KODE_PANGKAT_TERAKHIR AND gaji.MASA_KERJA_GOLONGAN = pegawai.MASA_KERJA_THN_AKHIR AND pangkat_golongan.KODE_PANGKAT = pegawai.KODE_PANGKAT_TERAKHIR;
and there's always error on this line
STR_TO_DATE(TAHUN_HITUNG, BULAN_HITUNG, '01','%Y-%m-%d') AS TMT_HITUNG
Error Code: 1582
Incorrect parameter count in the call to native function 'STR_TO_DATE'
As the MySQL documentation states, the STR_TO_DATE function takes only two parameters. MySQL STR_TO_DATE The first parameter should be the string that you want to convert, and the second is the date format. It looks like you have the second and not the first.
Do you mean to concatenate the year, month, and date? Try this:
STR_TO_DATE(concat(TAHUN_HITUNG,'-', BULAN_HITUNG,'-', '01'),'%Y-%m-%d') AS TMT_HITUNG
UPDATE
I made your main query a subquery, and then applied the str_to_date function on the results of the subquery, selecting all of the other columns. You could also add your tahun_hitung and bulan_hitung to the first select list. You can't use aliases for your calculations as column names within the same select statement. That's why you were getting the unknown column error.
select NIP_BARU, NAMA_PEGAWAI, KODE_PANGKAT_TERAKHIR, NAMA_PANGKAT,
GOLONGAN, MASA_KERJA_THN_AKHIR, MASA_KERJA_GOLONGAN, NOMINAL_GAJI,
STR_TO_DATE(concat(TAHUN_HITUNG,'-', BULAN_HITUNG,'-', '01'),'%Y-%m-%d') AS TMT_HITUNG
from (
SELECT DISTINCT pegawai.NIP_BARU, pegawai.NAMA_PEGAWAI, pegawai.KODE_PANGKAT_TERAKHIR,pangkat_golongan.NAMA_PANGKAT, pangkat_golongan.GOLONGAN, pegawai.MASA_KERJA_THN_AKHIR, gaji.MASA_KERJA_GOLONGAN, gaji.NOMINAL_GAJI,CASE PEGAWAI.TMT_GOL
WHEN (pangkat_golongan.JENIS_GOLONGAN = '2') AND pegawai.MASA_KERJA_THN_AKHIR MOD 2 = 0 AND 12 - pegawai.MASA_KERJA_BLN_AKHIR + MONTH(pegawai.TMT_GOL)> 12 THEN 2 + YEAR(pegawai.TMT_GOL)
WHEN (pangkat_golongan.JENIS_GOLONGAN = '1') AND pegawai.MASA_KERJA_THN_AKHIR MOD 2 = 1 AND 12 - pegawai.MASA_KERJA_BLN_AKHIR + MONTH(pegawai.TMT_GOL)> 12 THEN 2 + YEAR(pegawai.TMT_GOL)
WHEN (pangkat_golongan.JENIS_GOLONGAN = '1') AND pegawai.MASA_KERJA_THN_AKHIR MOD 2 = 0 AND 12 - pegawai.MASA_KERJA_BLN_AKHIR + MONTH(pegawai.TMT_GOL)< 12 THEN YEAR(pegawai.TMT_GOL)
WHEN (pangkat_golongan.JENIS_GOLONGAN = '2') AND pegawai.MASA_KERJA_THN_AKHIR MOD 2 = 1 AND 12 - pegawai.MASA_KERJA_BLN_AKHIR + MONTH(pegawai.TMT_GOL)< 12 THEN YEAR(pegawai.TMT_GOL)
ELSE 1 + YEAR(pegawai.TMT_GOL) END AS TAHUN_HITUNG,CASE PEGAWAI.MASA_KERJA_BLN_AKHIR
WHEN (12 -(pegawai.MASA_KERJA_BLN_AKHIR) + MONTH(pegawai.TMT_GOL) > 12)
THEN (12 - (pegawai.MASA_KERJA_BLN_AKHIR) + MONTH(pegawai.TMT_GOL) - 12)
ELSE (12 - (pegawai.MASA_KERJA_BLN_AKHIR) + MONTH(pegawai.TMT_GOL)) END AS BULAN_HITUNG
FROM pegawai, gaji, pangkat_golongan
WHERE gaji.KODE_GOLONGAN = pegawai.KODE_PANGKAT_TERAKHIR AND gaji.MASA_KERJA_GOLONGAN = pegawai.MASA_KERJA_THN_AKHIR AND pangkat_golongan.KODE_PANGKAT = pegawai.KODE_PANGKAT_TERAKHIR
) subquery;
You pass 4 params here:
STR_TO_DATE(TAHUN_HITUNG, BULAN_HITUNG, '01','%Y-%m-%d')
mysql doc here

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;

MySQL - my months are current stored 0-11

I thought I ran into a bug with MySQL 5.1, but the bug was in the perl code that's creating the timestamps. perl's localtime uses 0-11 for months, but MySQL's datetime uses 1-12. So, I've got all these malformed timestamps that I need to update.
2012-00-19 09:03:30
This should be:
2012-01-19 09:03:30
The problem is that the date functions for MySQL return NULL on a 00 month. Is there a way to do this in MySQL?
EDIT: Solution =
UPDATE test_stats
SET start_time = CAST(CONCAT(SUBSTRING(start_time, 1, 5),
CAST((CAST(SUBSTRING(start_time, 6, 2) AS UNSIGNED) + 1) AS CHAR(2)),
SUBSTRING(start_time, 8, 12)) AS DATETIME);
By the way, I was using MySQL 5.1
This should work:
UPDATE MyTable
SET DateTimeField =
CAST (
SUBSTRING(DateTimeString, 1, 5) -- '2012-'
+ CAST((CAST(SUBSTRING(DateTimeString, 6, 2) AS INT) + 1) AS VARCHAR) -- '00' => '1'
+ SUBSTRING(DateTimeString, 8, 12) -- '-19 09:03:30'
AS DATETIME)
Test with this select
DECLARE #x VARCHAR(50) = '2012-00-19 09:03:30'
SELECT CAST(SUBSTRING(#x, 1, 5)
+ CAST((CAST(SUBSTRING(#x, 6, 2) AS INT) + 1) AS VARCHAR)
+ SUBSTRING(#x, 8, 12) AS DATETIME)