Select from derived table sql exception - sql

I'm trying to execute a select statement from derived table as follows in MSSQL SERVER 2005:
The problem I try to solve is that there are duplicate rows but they differ in DATE field by seconds but i take minutes into account for example
ID DATE
1 08:20:00
1 08:20:01
2 09:21:00
5 10:00:00
5 10:00:01
I want to take DISTINCT values of ID's, and order by DATE but as i order by date I need to include DATE field. So i cant select distinctly on one column.
Derived table query (works by itself perfectly retrieving duplicates)
SELECT p.[SICIL] AS ID, h.[ZAMAN_TRH] AS ZAMAN_TRH
FROM [RF_BIO].[dbo].[PERSONEL] p, [RF_BIO].[dbo].[HAREKETLER] h
WHERE h.[ZAMAN_TRH] > '2013-05-27T00:00:00.000' AND h.[YON]= 2 AND
(p.[KARTNO] = h.[KARTNO] OR p.[SICIL]= h.[SICIL])
ORDER BY h.[ZAMAN_TRH] DESC
The query that uses the derived table:
SELECT DISTINCT [SICIL]
FROM ( SELECT p.[SICIL] AS SICIL, h.[ZAMAN_TRH] AS ZAMAN_TRH
FROM [RF_BIO].[dbo]. [PERSONEL] p, [RF_BIO].[dbo].[HAREKETLER] h
WHERE h.[ZAMAN_TRH] > '2013-05-27T00:00:00.000' AND h.[YON]= 2 AND
(p.[KARTNO] = h.[KARTNO] OR p.[SICIL]= h.[SICIL]) ORDER BY h.[ZAMAN_TRH] DESC ) AS LAST
This gets me sql exception in Java
java.sql.SQLException:
at net.sourceforge.jtds.jdbc.SQLDiagnostic.addDiagnostic(SQLDiagnostic.java:372)
at net.sourceforge.jtds.jdbc.TdsCore.tdsErrorToken(TdsCore.java:2893)
at net.sourceforge.jtds.jdbc.TdsCore.nextToken(TdsCore.java:2335)
at net.sourceforge.jtds.jdbc.TdsCore.getMoreResults(TdsCore.java:638)
at net.sourceforge.jtds.jdbc.JtdsStatement.executeSQLQuery(JtdsStatement.java:505)
at net.sourceforge.jtds.jdbc.JtdsStatement.executeQuery(JtdsStatement.java:1427)
Thank you for your help.

Use GROUP BY clause with aggregate function in the ORDER BY clause
SELECT p.[ID] AS ID
FROM [RF_BIO].[dbo].[PERSONEL] p, [RF_BIO].[dbo].[HAREKETLER] h
WHERE h.[DATE] > '2013-05-27T00:00:00.000' AND h.[YON]= 2
AND (p.[KART] = h.[KART] OR p.[ID]= h.[ID])
GROUP BY p.[ID]
ORDER BY MAX(h.[DATE]) DESC
Simple demo on SQLFiddle
SELECT p.[SICIL] AS SICIL
FROM [RF_BIO].[dbo].[PERSONEL] p, [RF_BIO].[dbo].[HAREKETLER] h
WHERE h.[ZAMAN_TRH] > '2013-05-27T00:00:00.000' AND h.[YON]= 2
AND (p.[KARTNO] = h.[KARTNO] OR p.[SICIL]= h.[SICIL])
GROUP BY p.[SICIL]
ORDER BY MAX(h.[ZAMAN_TRH]) DESC
Plan Diagram

Related

Count query with timestamp value

I would like to create a count query (in Postgres) which counts data.data_name dependent on data.todb_date.
So what I want to is that the query counts all the rows that are higher than the requirement in the WHERE clause. I tried Count(data.data_name) and Count(*) but they didn't work.
My planned result looks like this:
todb_date: 2016-01-01
data.data_name : test1
count: 150
todb_date: 2017-01-01
data.data_name : test1
count: 130
This is the query I have tried:
SELECT data.data_name, parentdata.data_id,
data.data_id, parentdata.todb_date,
COUNT (data.data_name)
FROM parentdata, data
WHERE parentdata.data_id = data.data_id
AND parentdata.todb_date > '2016-01-01'
GROUP BY parentdata.data_id, data.data_id, data.data_name, parentdata.todb_date
As #Usagi Miyamoto suggested, you should use a data_trunc() function to group your results according to certain time increments (here: per year):
SELECT d.data_name nam, date_trunc('year',p.todb_date) yr, COUNT(*) cnt
FROM parentdata p
INNER JOIN data d ON p.data_id = d.data_id AND p.todb_date > '2016-01-01'
GROUP BY d.data_name,date_trunc('year',p.todb_date)
ORDER BY nam, yr
If you replace 'year' by 'date' you will get daily counts, see here.

Postgres: Making column in first row contain sum of same column in other rows

I'm a newbie in postgres and i have a troubling issue.
Suppose the output of my SQL query is
123456789;"2014-11-20 12:30:35.454875";500;200;"2014-11-16 16:16:26.976258";300
123456789;"2014-11-20 12:30:35.454875";500;200;"2014-11-16 16:16:27.173523";100
What i want is to sum up all the 4th column, and so that the first row will contain the sum of the 4th column
123456789;"2014-11-20 12:30:35.454875";500;400;"2014-11-16 16:16:26.976258";300
My query is
select l.phone_no, l.loan_time, l.cents_loaned/100, r.cents_deducted/100, r.event_time,
r.cents_balance/100
from tbl_table1 l
LEFT JOIN tbl_table2 r
ON l.tb1_id = r.tbl2_id
where l.phone_no=123456789
order by r.event_time desc
Any help will be appreciated.
Maybe this helps. It will add a new row containing the sum of the 4th column.
WITH query AS (
SELECT l.phone_no, l.loan_time, l.cents_loaned/100 AS cents_loaned,
r.cents_deducted/100 AS cents_deducted, r.event_time,
r.cents_balance/100 AS cents_balance,
ROW_NUMBER() OVER (ORDER BY r.event_time DESC) rn,
SUM(cents_deducted/100) OVER () AS sum_cents_deducted
FROM tbl_table1 l
LEFT
JOIN tbl_table2 r
ON l.tb1_id = r.tbl2_id
WHERE l.phone_no=123456789
)
SELECT phone_no, loan_time, cents_loaned, cents_deducted, event_time, cents_balance
FROM query
WHERE rn > 1
UNION
ALL
SELECT phone_no, loan_time, cents_loaned, sum_cents_deducted, event_time, cents_balance
FROM query
WHERE rn = 1
Use a window function over the whole set (OVER ()) as frame:
select l.phone_no, l.loan_time, l.cents_loaned/100
, sum(r.cents_deducted) OVER () / 100 AS total_cents_deducted
, r.event_time, r.cents_balance/100
FROM tbl_table1 l
LEFT JOIN tbl_table2 r ON l.tb1_id = r.tbl2_id
WHERE l.phone_no = 123456789
ORDER BY r.event_time desc
This will return all rows, not just the first. Your question is unclear as to that.

Error while using group by

In table A I have the dates, and in B I have the order numbers.
In both tables I have a common field called order Id.
I just have a simple goal to fetch the number of orders on each date[ as in 1st, 2nd ..]
Here is what I have tried as I dont want to use joins or views.
select
A.date_of_order,
count(B.order_number)
from A, B
where A.order_id=B.order_id;
group by A.date_of_order
I am getting the following error. Probably making some trivial error. Thanks in advance
Update:
After taking into consideration Dmitri and rafa s suggestions, I get the table as:
23-FEB-14 1
23-FEB-14 1
23-FEB-14 2
23-FEB-14 2
23-FEB-14 2
07-MAR-14 2
07-MAR-14 4
07-MAR-14 1
07-MAR-14 5
02-MAR-14 1
02-MAR-14 1
As I said my requirement is very simple, just get it as
23-Feb-14 10[i.e. all the orders placed on this date]
07-Mar-14 13
02-mar-14 2
WHERE should be put before GROUP BY:
select A.date_of_order,
count(B.order_number)
from A, B
where A.order_id = B.order_id -- <- possible, but join will be better here
group by A.date_of_order
If you want a condition after GROUP BY you should use HAVING
select A.date_of_order,
count(B.order_number)
from A, B
where A.order_id = B.order_id
group by A.date_of_order
having count(B.order_number) < 3 -- having demo
The WHERE clause must to be before of the GROUP BY clause.
Use TRUNC(date) to get rid of the time so the GROUP BY will work as expected.
SELECT TRUNC(A.date_of_order), COUNT(B.order_number)
FROM A, B
WHERE A.order_id=B.order_id
GROUP BY TRUNC(A.date_of_order)
Anyway it is recommended to use the ANSI-standard SQL JOIN clause instead.
SELECT TRUNC(A.date_of_order), COUNT(B.order_number)
FROM A INNER JOIN B ON A.order_id = B.order_id
-- (WHERE conditions here)
GROUP BY TRUNC(A.date_of_order)
-- (HAVING conditions here)
The possible reasons could be that
1) Dates have timestamp, in that case following query would be helpful:
select
trunc(A.date_of_order),
count(B.order_number)
from A, B
where A.order_id=B.order_id
group by trunc(A.date_of_order);
2) Since in your sample data, you already have count against the dates, you need to take sum instead of count for your query
select
A.date_of_order,
sum(B.order_number)
from A, B
where A.order_id=B.order_id
group by A.date_of_order;
3) Or could be both, in that case you can try
select
trunc(A.date_of_order),
sum(B.order_number)
from A, B
where A.order_id=B.order_id
group by trunc(A.date_of_order);
I don't see why you need to join to that other table at all. Try just running:
select date_of_order, count(order_id) from tbl_a group by date_of_order
Your question states that table A contains rows for each order ID and date, and all you want to do is count the number of orders by date.

Select Top 5 records of every employee in SQL Server

I have the following issue, I have this query that select the latest 5 records created for an employee:
SELECT TOP 5
p.value,
p.record_date AS FECHA
FROM
employee_loan_movements p
WHERE
p.employee_code = '1'
AND p.record_date <= '2009-11-11'
AND p.movement_type = 1
AND p.value > 0
ORDER BY p.record_date DESC
Now i need to build a query to select the top 5 of every employee in the loan_movements table, I know i can do it in Oracle by selecting selecting rownum and rownum <= 5 but I cant manage to find a way to do that or something else with the same result in SQL Server 2000.
I guess I could use a function but I want to know first if it can be done in plain SQL.
Thanks for the help...
I answered before noticing you're on SQL Server 2000, so you couldn't take advantage of ROW_NUMBER. However, this MS Knowledgebase article gives examples how to artificially rank rows.
Once you have the ranking working, use the query in an inline view:
SELECT x.*
FROM (SELECT p.value,
... 'rank'
FROM EMPLOYEE_LOAN_MOVEMENTS p) x
WHERE x.rank <= 5
Not in SQL 2000, you can not do that. In SQL 2005/8 however you can:
WITH foo(eid) as (select distinct employee_code from employee_loan_movements)
SELECT * FROM foo
CROSS APPLY (
SELECT TOP 5
p.value,
p.record_date AS FECHA
FROM
employee_loan_movements p
WHERE
p.employee_code = foo.employee_code
AND p.record_date <= '2009-11-11'
AND p.movement_type = 1
AND p.value > 0
ORDER BY p.record_date DESC
)

Variant use of the GROUP BY clause in TSQL

Imagine the following schema and sample data (SQL Server 2008):
OriginatingObject
----------------------------------------------
ID
1
2
3
ValueSet
----------------------------------------------
ID OriginatingObjectID DateStamp
1 1 2009-05-21 10:41:43
2 1 2009-05-22 12:11:51
3 1 2009-05-22 12:13:25
4 2 2009-05-21 10:42:40
5 2 2009-05-20 02:21:34
6 1 2009-05-21 23:41:43
7 3 2009-05-26 14:56:01
Value
----------------------------------------------
ID ValueSetID Value
1 1 28
etc (a set of rows for each related ValueSet)
I need to obtain the ID of the most recent ValueSet record for each OriginatingObject. Do not assume that the higher the ID of a record, the more recent it is.
I am not sure how to use GROUP BY properly in order to make sure the set of results grouped together to form each aggregate row includes the ID of the row with the highest DateStamp value for that grouping. Do I need to use a subquery or is there a better way?
You can do it with a correlated subquery or using IN with multiple columns and a GROUP-BY.
Please note, simple GROUP-BY can only bring you to the list of OriginatingIDs and Timestamps. In order to pull the relevant ValueSet IDs, the cleanest solution is use a subquery.
Multiple-column IN with GROUP-BY (probably faster):
SELECT O.ID, V.ID
FROM Originating AS O, ValueSet AS V
WHERE O.ID = V.OriginatingID
AND
(V.OriginatingID, V.DateStamp) IN
(
SELECT OriginatingID, Max(DateStamp)
FROM ValueSet
GROUP BY OriginatingID
)
Correlated Subquery:
SELECT O.ID, V.ID
FROM Originating AS O, ValueSet AS V
WHERE O.ID = V.OriginatingID
AND
V.DateStamp =
(
SELECT Max(DateStamp)
FROM ValueSet V2
WHERE V2.OriginatingID = O.ID
)
SELECT OriginatingObjectID, id
FROM (
SELECT id, OriginatingObjectID, RANK() OVER(PARTITION BY OriginatingObjectID
ORDER BY DateStamp DESC) as ranking
FROM ValueSet)
WHERE ranking = 1;
This can be done with a correlated sub-query. No GROUP-BY necessary.
SELECT
vs.ID,
vs.OriginatingObjectID,
vs.DateStamp,
v.Value
FROM
ValueSet vs
INNER JOIN Value v ON v.ValueSetID = vs.ID
WHERE
NOT EXISTS (
SELECT 1
FROM ValueSet
WHERE OriginatingObjectID = vs.OriginatingObjectID
AND DateStamp > vs.DateStamp
)
This works only if there can not be two equal DateStamps for a OriginatingObjectID in the ValueSet table.