Trying to run this in Oracle 8i - sql

I'm trying to run this query in Oracle 8i but it's not working!
SELECT DECODE(seqnum, 1, t.ID1,cnt,'0') PI_VALUE1,
DECODE(seqnum, 1, t.STARTTIME,cnt,t.ENDTIME) timestamp,
'090.'
|| t2.APP
|| '.BATCH' tagname
FROM
(SELECT t.*,
row_number() over(partition BY t.ID1, t.PLANT_UNIT order by t.STARTTIME) AS seqnum,
COUNT(*) over(partition BY t.ID1, t.PLANT_UNIT) cnt
FROM tb_steps t
) t
INNER JOIN tb_equipments t2
ON t2.plant_unit = t.plant_unit
WHERE (seqnum = 1
OR SEQNUM = CNT)
AND (T.STARTTIME > '15-jul-2013'
AND t.ENDTIME < '15-aug-2013') ;
I've already made a lot of changes [like changing case when for decode] but it's still not OK...
Can someone help me write the query to be supported by Oracle 8i?
PS.: I know this version is not supported by Oracle for AGES but I'm only querying data for my .NET application so I can't upgrade/touch the DB.
Version is 8.1.7 and the specific error:
ORA-00933: SQL command not properly ended.
Many thanks,

ANSI joins were not introduced until Oracle Database 9iR1 (9.0.1). They are not supported in 8.1.7.
Try re-writing the query without an ANSI style join.
Something like this may work:
SELECT DECODE(seqnum, 1, t.ID1,cnt,'0') PI_VALUE1,
DECODE(seqnum, 1, t.STARTTIME,cnt,t.ENDTIME) timestamp,
'090.'
|| t2.APP
|| '.BATCH' tagname
FROM
(SELECT t.*,
row_number() over(partition BY t.ID1, t.PLANT_UNIT order by t.STARTTIME) AS seqnum,
COUNT(*) over(partition BY t.ID1, t.PLANT_UNIT) cnt
FROM tb_steps t
) t, tb_equipments t2
WHERE t2.plant_unit = t.plant_unit
AND (t.seqnum = 1
or t.seqnum = t.cnt)
AND (T.STARTTIME > '15-jul-2013'
AND t.ENDTIME < '15-aug-2013') ;
Totally untested....
Hope that helps.

Related

SQL Server LEAD function

-- FIRST LOGIN DATE
WITH CTE_FIRST_LOGIN AS
(
SELECT
PLAYER_ID, EVENT_DATE,
ROW_NUMBER() OVER (PARTITION BY PLAYER_ID ORDER BY EVENT_DATE ASC) AS RN
FROM
ACTIVITY
),
-- CONSECUTIVE LOGINS
CTE_CONSEC_PLAYERS AS
(
SELECT
PLAYER_ID,
LEAD(EVENT_DATE,1) OVER (PARTITION BY EVENT_DATE ORDER BY EVENT_DATE) NEXT_DATE
FROM
ACTIVITY A
JOIN
CTE_FIRST_LOGIN C ON A.PLAYER_ID = C.PLAYER_ID
WHERE
NEXT_DATE = DATEADD(DAY, 1, A.EVENT_DATE) AND C.RN = 1
GROUP BY
A.PLAYER_ID
)
-- FRACTION
SELECT
NULLIF(ROUND(1.00 * COUNT(CTE_CONSEC.PLAYER_ID) / COUNT(DISTINCT PLAYER_ID), 2), 0) AS FRACTION
FROM
ACTIVITY
JOIN
CTE_CONSEC_PLAYERS CTE_CONSEC ON CTE_CONSEC.PLAYER_ID = ACTIVITY.PLAYER_ID
I am getting the following error when I run this query.
[42S22] [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Invalid column name 'NEXT_DATE'. (207) (SQLExecDirectW)
This is a leetcode medium question 550. Game Play Analysis IV. I wanted to know why it can't identify the column NEXT_DATE here and what am I missing? Thanks!
The problem is in this CTE:
-- CONSECUTIVE LOGINS prep
CTE_CONSEC_PLAYERS AS (
SELECT
PLAYER_ID,
LEAD(EVENT_DATE,1) OVER (PARTITION BY EVENT_DATE ORDER BY EVENT_DATE) NEXT_DATE
FROM ACTIVITY A
JOIN CTE_FIRST_LOGIN C ON A.PLAYER_ID = C.PLAYER_ID
WHERE NEXT_DATE = DATEADD(DAY, 1, A.EVENT_DATE) AND C.RN = 1
GROUP BY A.PLAYER_ID
)
Note that you are creating NEXT_DATE as a column alias in this CTE but also referring to it in the WHERE clause. This is invalid because by SQL clause-ordering rules the NEXT_DATE column alias does not exist until you get to the ORDER BY clause which is the last evaluated clause in a SQL query or subquery. You don't have an ORDER BY clause in this subquery, so technically the NEXT_DATE column alias only exists to [sub]queries that both come after and reference your CTE_CONSEC_PLAYERS CTE.
To fix this you'd probably want two CTEs like this (untested):
-- CONSECUTIVE LOGINS
CTE_CONSEC_PLAYERS_pre AS (
SELECT
PLAYER_ID,
RN,
EVENT_DATE,
LEAD(EVENT_DATE,1) OVER (PARTITION BY EVENT_DATE ORDER BY EVENT_DATE) NEXT_DATE
FROM ACTIVITY A
JOIN CTE_FIRST_LOGIN C ON A.PLAYER_ID = C.PLAYER_ID
)
-- CONSECUTIVE LOGINS
CTE_CONSEC_PLAYERS AS (
SELECT
PLAYER_ID,
MAX(NEXT_DATE) AS NEXT_DATE,
FROM CTE_CONSEC_PLAYERS_pre
WHERE NEXT_DATE = DATEADD(DAY, 1, EVENT_DATE) AND RN = 1
GROUP BY PLAYER_ID
)
You gave every table an alias (for example JOIN CTE_FIRST_LOGIN C has the alias C), and every column access is via the alias. You need to add the correct alias from the correct table to NEXT_DATE.
Your primary issue is that NEXT_DATE is a window function, and therefore cannot be referred to in the WHERE because of SQL's order of operations.
But it seems this query is over-complicated.
The problem to be solved appears to be: how many players logged in the day after they first logged in, as a percentage of all players.
This can be done in a single pass (no joins), by using multiple window functions together:
WITH CTE_FIRST_LOGIN AS (
SELECT
PLAYER_ID,
EVENT_DATE,
ROW_NUMBER() OVER (PARTITION BY PLAYER_ID ORDER BY EVENT_DATE) AS RN,
-- if EVENT_DATE is a datetime and can have multiple per day then group by CAST(EVENT_DATE AS date) first
LEAD(EVENT_DATE, 1) OVER (PARTITION BY EVENT_DATE ORDER BY EVENT_DATE) AS NextDate
FROM ACTIVITY
),
BY_PLAYERS AS (
SELECT
c.PLAYER_ID,
SUM(CASE WHEN c.RN = 1 AND c.NextDate = DATEADD(DAY, 1, c.EVENT_DATE)
THEN 1 END) AS IsConsecutive
FROM CTE_FIRST_LOGIN AS c
GROUP BY c.PLAYER_ID
)
SELECT ROUND(
1.00 *
COUNT(c.IsConsecutive) /
NULLIF(COUNT(*), 0)
,2) AS FRACTION
FROM BY_PLAYERS AS c;
You could theoretically merge BY_PLAYERS into the outer query and use COUNT(DISTINCT but splitting them feels cleaner

SQL Time Attendance Query

Recently I made a switch from MS Access to SQL Server. Due to this switch I am having issues with making one SQL query to work.
This is how the current table looks like in SQL.
This is what I am trying to get as result from the query:
Previously I was able to make it work in MS Access with the following query:
SELECT m.UserEnrollNumber, m.Checktime AS TimeIn, (SELECT Min(s.Checktime)
FROM CheckInOut1 s
WHERE s.UserEnrollNumber = m.UserEnrollNumber
AND s.Checktime > m.Checktime
AND s.Checktime <= Int(m.Checktime) + 1) AS TimeOut
FROM CheckInOut1 AS m
WHERE ((((SELECT COUNT(*)
FROM CheckInOut1 s
WHERE s.UserEnrollNumber = m.UserEnrollNumber
AND s.Checktime <= m.Checktime
AND s.Checktime >= INT(m.Checktime)) Mod 2)=1));
The following query as answer from #GMB:
select
employee_id,
min(time_in_out) check_in,
max(time_in_out) check_out
from (
select t.*, row_number() over(partition by employee_id order by time_in_out) - 1 rn
from mytable t
) t
group by employee_id, floor(rn / 2)
order by employee_id, floor(rn / 2)
from SQL table:
gives me the following result:
Seems like the minimum and maximum rows are shown, but the rows in between are not.
The following query from #Gordon Linoff:
SELECT cio.EmployeeID, cio.TimeInOut AS CheckIn,
cio.TimeInOut as CheckOut
FROM (SELECT cio.*,
ROW_NUMBER() OVER (PARTITION BY cio.EmployeeID, CONVERT(date, cio.TimeInOut) ORDER BY cio.TimeInOut) as seqnum,
LEAD(cio.TimeInOut) OVER (PARTITION BY cio.EmployeeID, CONVERT(date, cio.TimeInOut) ORDER BY cio.TimeInOut) as next_TimeInOut
FROM CheckInOut22 cio
) cio
WHERE seqnum % 2 = 1;
Gives me the following result:
Checkin is the same as CheckOut.
All help would be appreciated.
This is much simpler in SQL Server. Use window functions:
SELECT cio.EmployeeID, cio.TimeInOut AS CheckIn,
cio.next_TimeInOut as CheckOut
FROM (SELECT cio.*,
ROW_NUMBER() OVER (PARTITION BY cio.EmployeeID, CONVERT(date, cio.TimeInOut) ORDER BY cio.TimeInOut) as seqnum,
LEAD(cio.TimeInOut) OVER (PARTITION BY cio.EmployeeID, CONVERT(date, cio.TimeInOut) ORDER BY cio.TimeInOut) as next_TimeInOut
FROM CheckInOut cio
) cio
WHERE seqnum % 2 = 1;

SQL DISTINCT Column with 2nd Criteria as datetime

I have on just started learning SQL in SQL Server Management Studio and getting thrown into the deep end.
I just need unique DriverID that has a LogoffTime in the last 3 month, with the headings included below.
What I have so far:
SELECT
Dr.DriverName, Dr.DriverNumber, Dr.DriverID,
DL.DriverID, DL.LogoffTime,
ROW_NUMBER() OVER (PARTITION BY DL.DriverID ORDER BY DL.LogoffTime DESC) AS rn
FROM
Taxihistory.dbo.DriverLogon DL, Taxihistory.dbo.Driver Dr
WHERE
DL.DriverID = Dr.DriverID
AND DL.LogoffTime <= '20180931'
AND rn = 1
ORDER BY
DL.LogoffTime DESC;
I am currently getting this error:
Msg 207, Level 16, State 1, Line 7
Invalid column name 'rn'
In case you want to explore CTE (Common Table Expression) option, you may also be able to achieve this with CTE. You can try something like below:
WITH CTE AS (
SELECT dr.drivername,
dr.drivernumber,
dr.driverid,
dl.logofftime,
row_number() OVER (PARTITION BY dl.driverid
ORDER BY dl.logofftime DESC) AS rn
FROM taxihistory.dbo.driverlogon dl
INNER JOIN taxihistory.dbo.driver dr
ON dr.driverid = dl.driverid
WHERE dl.logofftime <= Convert(datetime, '2018-09-30') )
SELECT tbl.drivername,
tbl.drivernumber,
tbl.driverid,
tbl.logofftime
FROM CTE tbl
WHERE tbl.rn = 1
ORDER BY tbl.logofftime DESC;
You cannot use column aliases in the WHERE clause. Neither can you use row_number() there. You have to wrap the query with the row_number() in a subquery and select from that.
SELECT x.drivername,
x.drivernumber,
x.driverid,
x.logofftime
FROM (SELECT dr.drivername,
dr.drivernumber,
dr.driverid,
dl.logofftime,
row_number() OVER (PARTITION BY dl.driverid
ORDER BY dl.logofftime DESC) rn
FROM taxihistory.dbo.driverlogon dl
INNER JOIN taxihistory.dbo.driver dr
ON dr.driverid = dl.driverid
WHERE dl.logofftime <= '20180930') x
WHERE x.rn = 1
ORDER BY x.logofftime DESC;
It is also advisable to use explicit join syntax. And I do hope, that driverlogon.logofftime is not an [n][var]char but some date/time type.
You should get the logon from the last 3 months up to the current date by doing so:
SELECT Dr.DriverName, Dr.DriverNumber, Dr.DriverID, DL.DriverID, DL.LogoffTime
FROM Taxihistory.dbo.DriverLogon DL,
INNER JOIN Taxihistory.dbo.Driver Dr ON DL.DriverID = Dr.DriverID
WHERE DL.LogOffTime < DATEADD(MONTH, -3, GETDATE())
ORDER BY DL.LogoffTime DESC;

How to add case in my query in SQL Server 2008 and 2012

I want to add case please help vehicle = 'Stop' addvalues start from starting, and it movingstatus = 'carmoving' values add contentiously in addvalues column
insert into TackHistory values(GETDATE(),GETDATE(),'Moving')
WITH rows AS
(
SELECT
*, ROW_NUMBER() OVER (ORDER BY gps_time) AS rn
FROM
TackHistory
WHERE
car_id = 12956
),
differences AS
(
SELECT
mc.rn, mc.gps_time, DATEDIFF(second, mc.gps_time, mp.gps_time) time_diff
FROM
rows mc
JOIN
rows mp ON mc.rn = mp.rn - 1
)
SELECT
t1.gps_time, t1.time_diff, SUM(t2.time_diff) time_sum
FROM
differences t1
INNER JOIN
differences t2 ON t1.rn >= t2.rn
GROUP BY
t1.rn, t1.gps_time, t1.time_diff
ORDER BY
t1.rn
SQL Server 2012 query
SELECT
gps_time,
DATEDIFF(second, LAG(gps_time) OVER (ORDER BY gps_time), gps_time) time_diff,
DATEDIFF(second, MIN(gps_time) OVER (ORDER BY gps_time), gps_time) time_sum
FROM
TackHistory
ORDER BY
gps_time

Connect by level for SQL Server 2008 like Oracle

nDays := Round( dEndTime - dStartTime ) + 1;
For i in 1..7 Loop
nDay := i + 1;
if i = 7 Then
nDay := 1;
End If;
SELECT To_Date(To_Char((dStartTime+Level-1),'DD.MM.YYYY')||' 00:00','DD.MM.YYYY HH24:MI'),
To_Date(To_Char((dStartTime+Level-1),'DD.MM.YYYY')||' 23:59','DD.MM.YYYY HH24:MI')
FROM DUAL
WHERE To_Char( dStartTime + Level -1 , 'd' ) = To_Char(nDay)
CONNECT BY Level <= nDays;
End Loop;
output:
22-JUL-12
23-JUL-12
18-JUL-12
19-JUL-12
20-JUL-12
21-JUL-12
I need to convert this query to SQL Server 2008, please help to find workaround with the same......
I have tried above output with single query with nDay from 1 to 7.....
You can do this with a recursive CTE. However, that syntax can be hard to remember, so when I need a handful of items, I do something like:
select *
from (select row_number() over (order by (select NULL)) as seqnum
from information_schema.columns
) t
where seqnum < <value>
Any table can be used. I just put in the INFORMATION_SCHEMA.columns table, because it is easy and generally has dozens or hundreds of rows.
Your output doesn't match the query. The following generates all dates between two values that are reasonably close together, Here is an example:
declare #dstarttime date = '2012-07-11', #dendtime date= '2012-07-13';
with const as (select #dstarttime as dStartTime, #dendtime as dendTime)
SELECT DATEADD(d, seqnum - 1, dStartTime)
FROM (select *
from (select row_number() over (order by (select NULL)) as seqnum, const.*
from information_schema.columns cross join const
) t
where seqnum <= DATEDIFF(d, dStartTime, dendTime) + 1
) t
As I said, you can also do this with recursive CTEs or, if you have one, with a calendar table.