SQL obtaining the last two digits of integer - sql

I need to obtain the last two digits of an integer. Each element placed in the tables comes as a full year ie. YYYY and I only want the last two digits, so that all the fields show
YEAR
----
09
00
89
where the initialy field was
YEAR
----
2009
2000
1989
EDIT: I get a complaint saying,
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
when i try
select right(cast(year as char),2) from subjects;

Postgres has borrowed (or inherited) the modulus operator from C:
SET search_path='tmp';
CREATE TABLE lutser ( year integer);
INSERT INTO lutser (year)
SELECT generate_series(1991,2012)
;
SELECT year
, year / 100 as c2
, year % 100 AS y2
FROM lutser
;
Result:
CREATE TABLE
INSERT 0 22
year | c2 | y2
------+----+----
1991 | 19 | 91
1992 | 19 | 92
1993 | 19 | 93
1994 | 19 | 94
1995 | 19 | 95
1996 | 19 | 96
1997 | 19 | 97
1998 | 19 | 98
1999 | 19 | 99
2000 | 20 | 0
2001 | 20 | 1
2002 | 20 | 2
2003 | 20 | 3
2004 | 20 | 4
2005 | 20 | 5
2006 | 20 | 6
2007 | 20 | 7
2008 | 20 | 8
2009 | 20 | 9
2010 | 20 | 10
2011 | 20 | 11
2012 | 20 | 12
(22 rows)

select substring(CAST(2012 as CHAR(4)), 3, 2)

I don't know if there is a LEN function on Postgres, but if it does, try this:
select SUBSTRING(year,len(year)-1,len(year))

You can also use below SQL query:
select to_char as year from to_char(current_timestamp, 'YY')
here we use last two digit of year from current_timestamp

Related

PostgreSQL calculate difference between multi rows

I tried to calculate difference between rows in a field using a query:
Illustrations:
input:year,month,name, size
output:increase
year | month | name | Size | increase
------+--------+------- -+-------+-----------
2020 | 01 | john |10 | 0
2020 | 01 | peter |12 | 0
2020 | 01 | kim |16 | 0
2020 | 02 | john |15 | 5 <- 15 - 10
2020 | 02 | peter |16 | 4 <- 16 - 12
2020 | 02 | kim |17 | 1 <- 17 - 16
2020 | 03 | john |18 | 3 <- 18 - 16
2020 | 03 | peter |19 | 3 <- 19 - 16
2020 | 03 | kim |77 | 60 <- 77 - 17
-------
2020 | 12 | john |25 | 17
2020 | 12 | peter |70 | 33
2020 | 12 | kim |90 |42
Increase column as output by difference between adjacent "name" rows in size.
Use LAG()
select year,
month,
name,
size,
size - lag(size) over (partition by name order by year, month) as increase
from MyTable
If you want 0s for the first set of rows, then use the 3-argument form of lag():
select year, month, name, size,
(size - lag(size, 1, size)) over (partition by name order by year, month) as increase
from MyTable;
Personally, I prefer NULL so I prefer JohnHC's answer. However, the question is explicitly asking for 0 values there.
Thanks JohnHC and Gorden for helping.
It works when I run the query on psql commandline. But when I put it into a php script:
$result = pg_query($conn,"select year, month, name, (size - lag(size, 1, size)) over (partition by name order by year, month). as increase from testdb ");
I get error message:
PHP Warning: pg_query(): Query failed: ERROR: syntax error at or near '- lag(size)......'

Calculate number of cells in row above threshold

I have a table like this:
Student_ID | Year | Math Grade | English Grade
----------------------------------------------
1 | 2009 | 90 | 92
2 | 2009 | 80 | 95
1 | 2010 | 75 | 85
I want to calculate the number grades a student got each year over 90. The desired output for the above table is:
Student_ID | Year | Math Grade | English Grade | Grades Above 90
----------------------------------------------------------------
1 | 2009 | 91 | 92 | 2
2 | 2009 | 80 | 95 | 1
1 | 2010 | 75 | 85 | 0
You should do this using a case statement:
select ((math_grade > 90 then 1 else 0 end) + (english_grade > 90 then 1 else 0 end)
) as grades_above_90
The problem with using division is that it doesn't work if the threshold is less than 50.
Figured out a pretty simple solution for this. I added to the end of my SELECT statement:
SELECT math_grade/90 + english_grade/90 AS grades_above_90

How to use previous row's column's value for calculating the next row's column's value

I have a table
Id | Aisle | OddEven | Bay | Size | Y-Axis
3 | A1 | Even | 14 | 10 | 100
1 | A1 | Even | 16 | 10 |
6 | A1 | Even | 20 | 10 |
12 | A1 | Even | 26 | 5 | 150
10 | A1 | Even | 28 | 5 |
11 | A1 | Even | 32 | 5 |
2 | A1 | Odd | 13 | 10 | 100
5 | A1 | Odd | 17 | 10 |
4 | A1 | Odd | 19 | 10 |
9 | A1 | Odd | 23 | 5 | 150
7 | A1 | Odd | 25 | 5 |
8 | A1 | Odd | 29 | 5 |
want to look like this
Id | Aisle | OddEven | Bay | Size | Y-Axis
1 | A1 | Even | 14 | 10 | 100
2 | A1 | Even | 16 | 10 | 110
3 | A1 | Even | 20 | 10 | 120
4 | A1 | Even | 26 | 5 | 150
5 | A1 | Even | 28 | 5 | 155
6 | A1 | Even | 32 | 5 | 160
7 | A1 | Odd | 13 | 10 | 100
8 | A1 | Odd | 17 | 10 | 110
9 | A1 | Odd | 19 | 10 | 120
10 | A1 | Odd | 23 | 5 | 150
11 | A1 | Odd | 25 | 5 | 155
12 | A1 | Odd | 29 | 5 | 160
I need a select query and update query. What its doing is there are already some Y-Axis Number been filled (at the start of the Odd/Even) then I need to take the previous row's Y-Axis column's value and adds to the current rows's size which = to current Y-Axis. Needs to keep doing it until it finds another Y-Axis has the value it skips the calculation and next row is using that number.
My thinking process is this:
Id will definitely be used, however, the Id is not sequence as shown my example
so I need to have
ROW_Number OVER (PARTITION BY Aisle,OddEven,Bay Order BY Aisle,OddEven,Bay)
Then some kind of JOIN the same table but the ON is T1.RN = T2.RN - 1
Where I am stuck is but the first row has not previous value it will try to update that value.
Anyone have an idea for SQL Query 2008 for Select and Update will be greatly appreciated! Thanks.
You seem to want a cumulative sum. This would be easier in SQL Server 2012+. You can do this in SQL Server 2008 using outer apply:
select t.*, cume_value
from t outer apply
(select sum(size) + sum(yaxis) as cume_value
from t t2
where t2.aisle = t.aisle and t2.oddeven = t.oddeven and
t2.bay < t.bay
) t2;
A little more difficult on 2008, but I think this is what you are looking for
Declare #Table table (Id int,Aisle varchar(25),OddEven varchar(25),Bay int,Size int,[Y-Axis] int)
Insert Into #Table values
(3,'A1','Even',14,10 ,100),
(1,'A1','Even',16,10 ,0),
(6,'A1','Even',20,10 ,0),
(12,'A1','Even',26,5,150),
(10,'A1','Even',28,5,0),
(11,'A1','Even',32,5,0),
(2,'A1','Odd',13,10 ,100),
(5,'A1','Odd',17,10 ,0),
(4,'A1','Odd',19,10 ,0),
(9,'A1','Odd',23,5,150),
(7,'A1','Odd',25,5,0),
(8,'A1','Odd',29,5,0)
;with cteBase as (
Select *
,IDNew=Row_Number() over (Order By Aisle,Bay)
,RowNr=Row_Number() over (Order By Aisle,OddEven,Bay)
From #Table
)
, cteGroup as (Select TmpRowNr=RowNr,GrpNr=Row_Number() over (Order By RowNr) from cteBase where [Y-Axis]>0)
, cteFinal as (
Select A.*
,GrpNr = (Select max(GrpNr) from cteGroup Where TmpRowNr<=RowNr)
From cteBase A
)
Select ID=Row_Number() over (Order By A.OddEven,A.Bay)
,A.Aisle
,A.OddEven
,A.Bay
,A.Size
,[Y-Axis] = Sum(case when B.[Y-Axis]>0 then B.[Y-Axis] else B.Size end)
From cteFinal A
Join cteFinal B on (B.RowNr<=A.RowNr and A.GrpNr=B.GrpNr)
Group By
A.IDNew
,A.Aisle
,A.OddEven
,A.Bay
,A.Size
Order By A.OddEven,A.Bay
Returns
ID Aisle OddEven Bay Size Y-Axis
1 A1 Even 14 10 100
2 A1 Even 16 10 110
3 A1 Even 20 10 120
4 A1 Even 26 5 150
5 A1 Even 28 5 155
6 A1 Even 32 5 160
7 A1 Odd 13 10 100
8 A1 Odd 17 10 110
9 A1 Odd 19 10 120
10 A1 Odd 23 5 150
11 A1 Odd 25 5 155
12 A1 Odd 29 5 160
I gotta leave my computer so update query should be easy to move on from here.
Below is the select query;
select row_number() over (order by oddeven,bay) id,
Aisle,
OddEven,
Bay,
Size,
max(ISNULL([Y-Axis],0)) over (partition by Aisle, OddEven,Size order by bay)
+ sum(CASE WHEN [Y-Axis] is null THEN Size ELSE 0 END) over (partition by Aisle,OddEven,size order by Bay) as [Y-Axis]
from oddseven
order by id

Access Concatenating Values in a Query

I have a query, [Query1], with employee names, projects, days, months, and years.
In another query, [Query2], I take all the values and put them into a cross table. My rows are "Year, Month, Employee." My column is "Day." My values are Projects.
The problem is that for one date, there may be more than one project assigned to an employee.
When I attempt to put the projects as values into a table using IIf(Count(*)>0,[Project],""), I get an error because there may be more than one possible value for the project, and access doesn't know which one to choose.
I need a way to Concatenate the values if there is more than one Project.
Ex:
[Query1]
Bill | CC555 | 28 | 03 | 2014
Jim | CC999 | 29 | 03 | 2014
Jim | CC555 | 29 | 03 | 2014
John | CC555 | 29 | 03 | 2014
[Query2]
Year | Month | Employee | 1 | 2 | 3 | ... | 27 | 28 | 29 | 30 | 31
2014 | 03 | Bill | - | - | - | ... | - | CC555 | - | - | -
2014 | 03 | Jim | - | - | - | ... | - | - | CC555 + CC999 | - | -
2014 | 03 | John | - | - | - | ... | - | - | CC555 | - | -
Aside: [Query1] is dynamic and could have duplicate dates deleted or added to it, so [Query2] values must change accordingly.
one simple example,you have to make it dynamic,in real scenrio no need of table variable or CTE if using dynamic sql.i think no need of dynamic,just hard code from 1 to 31
;With CTE as
(
select 'Bill' Employee ,'CC555' codes,28 dd,03 mm ,2014 yrs union all
select 'Jim ','CC999', 29 , 03 , 2014 union all
select 'Jim ','CC555', 29 , 03 , 2014 union all
select 'John','CC555', 29 , 03 , 2014
)
select yrs,mm,Employee,isnull([28],'-')[28],[29],[30] from
(select Employee,dd,mm,yrs
,stuff((select ','+codes from cte b where b.Employee=a.Employee for xml path('')),1,1,'')codes
from cte a ) src
pivot (min(codes) for dd in([28],[29],[30])) pvt
By using the function given here allenbrowne.com/func-concat.html, and following the example given here http://www.access-programmers.co.uk/forums/showthread.php?t=234291, I was able to solve the problem.

How to insert additional values in between a GROUP BY

i am currently making a monthly report using MySQL. I have a table named "monthly" that looks something like this:
id | date | amount
10 | 2009-12-01 22:10:08 | 7
9 | 2009-11-01 22:10:08 | 78
8 | 2009-10-01 23:10:08 | 5
7 | 2009-07-01 21:10:08 | 54
6 | 2009-03-01 04:10:08 | 3
5 | 2009-02-01 09:10:08 | 456
4 | 2009-02-01 14:10:08 | 4
3 | 2009-01-01 20:10:08 | 20
2 | 2009-01-01 13:10:15 | 10
1 | 2008-12-01 10:10:10 | 5
Then, when i make a monthly report (which is based by per month of per year), i get something like this.
yearmonth | total
2008-12 | 5
2009-01 | 30
2009-02 | 460
2009-03 | 3
2009-07 | 54
2009-10 | 5
2009-11 | 78
2009-12 | 7
I used this query to achieved the result:
SELECT substring( date, 1, 7 ) AS yearmonth, sum( amount ) AS total
FROM monthly
GROUP BY substring( date, 1, 7 )
But I need something like this:
yearmonth | total
2008-01 | 0
2008-02 | 0
2008-03 | 0
2008-04 | 0
2008-05 | 0
2008-06 | 0
2008-07 | 0
2008-08 | 0
2008-09 | 0
2008-10 | 0
2008-11 | 0
2008-12 | 5
2009-01 | 30
2009-02 | 460
2009-03 | 3
2009-05 | 0
2009-06 | 0
2009-07 | 54
2009-08 | 0
2009-09 | 0
2009-10 | 5
2009-11 | 78
2009-12 | 7
Something that would display the zeroes for the month that doesnt have any value. Is it even possible to do that in a MySQL query?
You should generate a dummy rowsource and LEFT JOIN with it:
SELECT *
FROM (
SELECT 1 AS month
UNION ALL
SELECT 2
…
UNION ALL
SELECT 12
) months
CROSS JOIN
(
SELECT 2008 AS year
UNION ALL
SELECT 2009 AS year
) years
LEFT JOIN
mydata m
ON m.date >= CONCAT_WS('.', year, month, 1)
AND m.date < CONCAT_WS('.', year, month, 1) + INTERVAL 1 MONTH
GROUP BY
year, month
You can create these as tables on disk rather than generate them each time.
MySQL is the only system of the major four that does have allow an easy way to generate arbitrary resultsets.
Oracle, SQL Server and PostgreSQL do have those (CONNECT BY, recursive CTE's and generate_series, respectively)
Quassnoi is right, and I'll add a comment about how to recognize when you need something like this:
You want '2008-01' in your result, yet nothing in the source table has a date in January, 2008. Result sets have to come from the tables you query, so the obvious conclusion is that you need an additional table - one that contains each month you want as part of your result.