SQL Server : error which works well in Oracle - sql-server

I'm migrating from an Oracle database to SQL Server 2012. Some SQL which works well in Oracle doesn't work with SQL Server.
The following is my SQL and the error.
SELECT
SUM(COUNT(DISTINCT dfc.rentalNumber))
FROM
DueFromClient dfc
WHERE
dfc.facilityId=:facilityId
AND dfc.isRentalComponent = 1
GROUP BY
dfc.rentalNumber
and the error is
Cannot perform an aggregate function on an expression containing an aggregate or a subquery

Remove the SUM from the query, as it has no use, since you are also using GROUP BY. The results will be the same as your original query.
SELECT
COUNT(DISTINCT dfc.rentalNumber)
FROM DueFromClient dfc
WHERE dfc.facilityId = facilityId
AND dfc.isRentalComponent = 1
GROUP BY dfc.rentalNumber
This doesn't make much sense, so I suggest also adding the rentalNumber to the SELECT in order to make sense of your data and to also make full use of the GROUP BY.
SELECT
COUNT(DISTINCT dfc.rentalNumber)
, dfc.rentalNumber
FROM DueFromClient dfc
WHERE dfc.facilityId = facilityId
AND dfc.isRentalComponent = 1
GROUP BY dfc.rentalNumber

You don't need to sum count and group by. Try this:
SELECT
COUNT(DISTINCT dfc.rentalNumber)
FROM
DueFromClient dfc
WHERE
dfc.facilityId=:facilityId
AND dfc.isRentalComponent = 1
sqlfiddle for this query
All of proposed below are suboptimal and returns same result as query above, but they may meet needs of #Sachi Pj with using of same construction as in original query with SUM(COUNT(DISTINCT()) two more options:
SELECT SUM(dfc2.rentalNumber)
FROM
(
SELECT
COUNT(DISTINCT dfc.rentalNumber) rentalNumber
FROM
DueFromClient dfc
WHERE
dfc.facilityId=:facilityId
AND dfc.isRentalComponent = 1
) AS dfc2
GROUP BY dfc2.rentalNumber
sqlfiddle for this query
And without GROUP BY since doubles was eliminated by distinct:
SELECT SUM(dfc2.rentalNumber)
FROM
(
SELECT
COUNT(DISTINCT dfc.rentalNumber) rentalNumber
FROM
DueFromClient dfc
WHERE
dfc.facilityId=:facilityId
AND dfc.isRentalComponent = 1
) AS dfc2
sqlfiddle for this query
You can compare with your original query sqlfiddle to being sure what the results are same.

Related

SQL Server : Update WHERE xxx AND most recent record

Similar to this question, but I require this in Microsoft SQL Server.
I'm looking to update values in my database, but only the most recently added value for each date.
For example if I have 4 rows where column_day = '2023-02-01',
and they have updated datetimes in a column [Time_Stamp] of
2023-01-01, 2023-01-27, 2023-01-10, and 2023-01-05,
I would like to only update the Jan 27, 2023 2023-01-27 line.
The answer provided here which does not work in Microsoft SQL Server is:
UPDATE your_table
SET some_column = 1
ORDER BY date_time_column DESC
LIMIT 1
My code I'm trying is slightly different as it includes a WHERE:
I get an error
Incorrect syntax near the keyword 'order'
UPDATE your_table
SET some_column = 1
WHERE column_tag = 'test' AND column_day = '2023-02-01'
ORDER BY Time_Stamp DESC
LIMIT 1
How can I achieve this in Microsoft SQL Server?
You can use TOP in an UPDATE, however, you can't provide an ORDER BY; as such it's really used for batching and previously UPDATEd rows are filtered in each iteration in the WHERE clause.
For what you want, one method would be to use an UPDATEable CTE with ROW_NUMBER:
WITH CTE AS(
SELECT SomeColumn,
ROW_NUMBER() OVER (ORDER BY date_time_column DESC) AS RN
FROM dbo.YourTable
WHERE ColumnTag = 'Test'
AND ColumnDay = '20230201')
UPDATE CTE
SET SomeColumn = 1
WHERE RN = 1;

Convert CROSS APPLY in DB2 database

I am trying to convert the below MSSQL query into DB2 query.
But i am facing issues . I got to know "CROSS APPLY" doesnt exist for DB2
SQL Server query:
SELECT DISTINCT p.ID,
p.COMPANY,
p.NAME,
format(d.startTime, 'yyyy-MM-dd HH:mm:ss.fff')
FROM PROCESS p
CROSS APPLY (SELECT MAX(END_TIME) AS startTime FROM PROCESS WHERE ID = (SELECT MAX(ID) FROM PROCESS)) AS d
WHERE p.ID = (SELECT MAX(ID) FROM PROCESS)
Error:
Error: com.ibm.db2.jcc.c.SqlException: DB2 SQL error: SQLCODE: -104, SQLSTATE: 42601, SQLERRMC: APPLY;N process
CROSS;JOIN
How the above query can be converted into DB2 query format?
The SQL Server manual says that a CROSS APPLY is used with table functions.
https://learn.microsoft.com/en-us/sql/t-sql/queries/from-transact-sql?view=sql-server-ver15#using-apply
That the right_table_source can use a table-valued function that takes a column from the left_table_source as one of the arguments of the function.
Your example does not use any, so I assume it is simply the equivalent to a CROSS JOIN in Db2.
By the way, this statement would likely get the same result (assuming COMPANY and NAME are the same for a given ID)
SELECT
ID
, COMPANY
, NAME
, format(END_TIME, 'yyyy-MM-dd HH:mm:ss.fff')
FROM
( SELECT *
, ROW_NUMBER() OVER(ORDER BY ID DESC, END_TIME DESC) AS RN
FROM
PROCESS p
)
WHERE
RN = 1
This might or might not be more optimal at execution time
The DB2 equivalent is the terribly named TABLE operator. The name makes it very challenging to find documentation.
See if this works for your query.
SELECT DISTINCT p.ID,
p.COMPANY,
p.NAME
FROM PROCESS p
JOIN TABLE (
SELECT ID
,MAX(END_TIME) AS startTime
FROM PROCESS
WHERE ID = (
SELECT MAX(ID)
FROM PROCESS
)
GROUP BY ID
) AS D
ON P.ID = D.ID
However, I've found CTEs in DB2 to be very effective. In SQL Server, a CTE is almost like a layer applied to a query, similar to a view. The expressions in the CTE are generally combined with the underlying statements and executed as a single statement.
I'm not a DB2 expert, but it seems to me that a CTE is materialized to an internal table and the result is combined with the remaining statements.
With the same query, data and indexes, DB2 and SQL Server can have very different performance when CTEs are involved.

how to convert sql query to hibernate query

i have q sql query where i am fetching data using subquery and left join. it is working properly on sql server but when i use this query in hibernate using HQL it says unexpected token (;
below is my query which is working fine on sql server -
SELECT IH.vendorName, IH.C, IHP.CP FROM (SELECT vendorName, count(*) as C
FROM InvoiceHeader GROUP BY vendorName) IH LEFT JOIN (SELECT vendorName,
count(*) AS CP FROM InvoiceHeader WHERE invoiceStatus='Processed' GROUP BY
vendorName) IHP ON IHP.vendorName=IH.vendorName ORDER BY IH.C DESC
here i am trying to convert my sql query to HQL
Query q = sessionFactory.getCurrentSession().createQuery("SELECT
IH.vendorName, IH.C, IHP.CP FROM (SELECT vendorName, count(*) as C FROM
InvoiceHeader GROUP BY vendorName) IH LEFT JOIN (SELECT vendorName, count(*)
AS CP FROM InvoiceHeader WHERE invoiceStatus='Processed' GROUP BY
vendorName) IHP ON IHP.vendorName=IH.vendorName ORDER BY IH.C DESC");
but i am getting this error at
org.hibernate.hql.internal.ast.ErrorCounter reportError
ERROR: line 1:41: unexpected token: (
org.hibernate.hql.internal.ast.ErrorCounter reportError
ERROR: line 1:61: unexpected token: count
Here's partially how to do it.
First, your query needs to be simplified, because the joins are not at all efficient. MSSQL does not support FILTER, but Modern SQL shows us a sufficent alternative.
SELECT vendorName, sum(case when invoiceStatus = 'Processed' then 1 end) as CP, count(*) as C FROM InvoiceHeader GROUP BY vendorName ORDER BY C DESC;
Secondly you could use createNativeQuery if it turns out to be impossible to translate it to HQL, but this is my attempt to do so:
SELECT I.vendorName, COUNT(I) as C, SUM(CASE WHEN I.invoiceStatus = 'Processed' THEN 1 END) AS CP FROM InvoiceHeader I GROUP BY I.vendorName ORDER BY C DESC
It is important you use the table alias, so that it will resolve properly within the query, even though it's the only table.

SQL duplicates with percentage result

I have an issue where my database contains a table with these columns:
Program_ID, Vehicle_VIN, Vehicle_Type
I need to create a report where will be:
Program_ID, AmountOfAllPoliciesInProgram, PercentageDuplicatesInProgram
where Vehicle_type = 10
and criteria for the duplicate is to have Vehicle_VIN more than 1 unique time in the table for dedicated Program_ID.
It's in Microsoft SQL Server Management Studio
AmountOfAllPoliciesInProgram is:
SELECT
PROGRAM_ID, COUNT(*) AS AmountOfAllPoliciesInProgram
FROM
dbo.table
WHERE
Vehicle_type = 10
GROUP BY
PROGRAM_ID
I'm not 100% sure I understand you correctly, but you can count distinct Vehicle_VIN and use the having clause to test if the count of distinct Vehicle_VIN is larger than 1. Like so,
SELECT PROGRAM_ID, COUNT(*) as AmountOfAllPoliciesInProgram, count(distinct Vehicle_VIN) as VIN_COUNT
FROM dbo.table
where Vehicle_type = 10
group by PROGRAM_ID
having count(distinct Vehicle_VIN)>1

How to create RowNum column in SQL Server?

In Oracle we have "rownum".
What can I do in SQL Server?
In SQL Server 2005 (and 2008) you can use the ROW_NUMBER function, coupled with the OVER clause to determine the order in which the rows should be counted.
Update
Hmm. I don't actually know what the Oracle version does. If it's giving you a unique number per row (across the entire table), then I'm not sure there's a way to do that in SQL Server. SQL Server's ROW_NUMBER() only works for the rows returned in the current query.
If you have an id column, you can do this:
select a.*,
(select count(*) from mytable b where b.id <= a.id) as rownum
from mytable a
order by id;
Of course, this only works where you're able to order rownums in the same (or opposite) order as the order of the ids.
If you're selecting a proper subset of rows, of course you need to apply the same predicate to the whole select and to the subquery:
select a.*,
(select count(*) from table b where b.id <= a.id and b.foo = 'X') as rownum
from table a where a.foo = 'X'
order by id;
Obviously, this is not particularly efficient.
Based on my understanding, you'd need to use ranking functions and/or the TOP clause. The SQL Server features are specific, the Oracle one combines the 2 concepts.
The ranking function is simple: here is why you'd use TOP.
Note: you can't WHERE on ROWNUMBER directly...
'Orable:
select
column_1, column_2
from
table_1, table_2
where
field_3 = 'some value'
and rownum < 5
--MSSQL:
select top 4
column_1, column_2
from
table_1, table_2
where
field_3 = 'some value'

Resources