Syntax errors in sybase query - sql

I have never used sybase before until today. I have a query in Access that is using First() and has multiple iif statements. I hoped for the best and pasted my query in and I am getting errors on the First() section. I removed the First's from the query, and I am getting errors on the iif statements.
Here is my query:
SELECT Client.ClientId, First(Trans.SysId) AS FirstOfSysId, Client.Name1,
Relation.Name1, Debtor.Name1, Account.AcctId, First(Trans.PostDate) AS FirstOfPostDate,
Sum(IIf([TransType]="uc",[Amount],IIf([TransType]="CA",[Amount],IIf([TransType]="RAC",
[Amount],IIf([TransType]="UCBR",[Amount],[amount]*-1))))) AS TransAmount,
Trans.CheckId,Relation.RelId
FROM (((Trans INNER JOIN Account ON Trans.SysAcctId = Account.SysId)
INNER JOIN Debtor ON Account.SysDtrId = Debtor.SysId)
INNER JOIN Relation ON Account.SysRelId = Relation.SysId) INNER JOIN Client ON
Relation.SysClientId = Client.SysId
WHERE (((Trans.TransType)="CA" Or (Trans.TransType)="NC" Or (Trans.TransType)="UC" Or
(Trans.TransType)="AC"
Or (Trans.TransType)="UCB" Or (Trans.TransType)="RAC" Or (Trans.TransType)="UCB" Or
(Trans.TransType)="UCBR"))
GROUP BY Client.ClientId, Client.Name1, Relation.Name1, Debtor.Name1, Account.AcctId,
Trans.CheckId, Relation.RelId
HAVING (((Client.ClientId)=[Forms]![frmCredit]![Combo112])
AND ((Sum(IIf([TransType]="uc",[Amount],IIf([TransType]="CA",[Amount],
IIf([TransType]="RAC", [Amount],IIf([TransType]="UCBR",[Amount],[amount]*-1))))))>0
Or (Sum(IIf([TransType]="uc",[Amount],IIf([TransType]="CA",[Amount],
IIf([TransType]="RAC", [Amount],IIf([TransType]="UCBR",[Amount],[amount]*-1))))))<0)
AND ((Relation.RelId) Not Like "281099"))
ORDER BY Relation.Name1, Account.AcctId, Trans.CheckId
[Edit] A more readable query has been added to http://sqlfiddle.com/#!2/4b98e0/1 [/Edit]
I can't find documentation on converting the first function, but with the IIF should I convert that to a Case when statement? I saw an article here, but I am not sure if it is the most efficient, since it is from 1999...
The error I am getting is Syntax error near 'FIRST' on line 1. Which based on the article here I am using it in the right syntax.
Any help on using First in the right syntax and if I should use a Case When instead of the iif is greatly appreciated.

Based on what I think the query does I think you can rewrite it as below. I don't have access to any Sybase server to validate the query, so I tried it on MS SQL but I commented out some stuff with /* */ that might not be needed with Sybase.
It might be completely wrong, or it might be correct. If it's wrong, please let me know in a comment and I'll remove my answer.
SELECT
Client.ClientId,
FIRST_VALUE(Trans.SysId) /* OVER (ORDER BY Trans.Sysid) */ AS FirstOfSysId,
Client.Name1,
Relation.Name1,
Debtor.Name1,
Account.AcctId,
FIRST_VALUE(Trans.PostDate) /* OVER (ORDER BY Trans.postdate) */ AS FirstOfPostDate,
SUM(CASE
WHEN [TransType] IN ('uc', 'CA', 'RAC', 'UCBR') THEN AMOUNT
ELSE AMOUNT * -1
END
) AS TransAmount,
Trans.CheckId,
Relation.RelId
FROM Trans
INNER JOIN Account ON Trans.SysAcctId = Account.SysId
INNER JOIN Debtor ON Account.SysDtrId = Debtor.SysId
INNER JOIN Relation ON Account.SysRelId = Relation.SysId
INNER JOIN Client ON Relation.SysClientId = Client.SysId
WHERE Trans.TransType IN ('CA','NC','UC','AC','UCB','RAC','UCB','UCBR')
GROUP BY
Client.ClientId, Client.Name1,
Relation.Name1, Debtor.Name1,
Account.AcctId, Trans.CheckId,
Relation.RelId /* , trans.sysid, trans.postdate */
HAVING
1=1 --AND (((Client.ClientId)=[Forms]![frmCredit]![Combo112])
AND SUM(
CASE WHEN [TransType] IN ('uc', 'CA', 'RAC', 'UCBR') THEN AMOUNT
ELSE AMOUNT * -1 END
) <> 0
AND Relation.RelId <> '281099'
ORDER BY Relation.Name1, Account.AcctId, Trans.CheckId
My reasoning here is that
Sum(IIf([TransType]="uc",[Amount],IIf([TransType]="CA",[Amount],IIf([TransType]="RAC",
[Amount],IIf([TransType]="UCBR",[Amount],[amount]*-1))))) AS TransAmount,
just takes theamountifTransTypeis any of'uc', 'CA', 'RAC', 'UCBR'elseAmount*-1 and this should be equivalent with:
SUM(CASE WHEN [TransType] IN ('uc', 'CA', 'RAC', 'UCBR') THEN AMOUNT
ELSE AMOUNT*-1 END) AS TransAmount,
and in thehavingclause this:
((Sum(IIf([TransType]="uc",[Amount],IIf([TransType]="CA",[Amount],
IIf([TransType]="RAC", [Amount],IIf([TransType]="UCBR",[Amount],[amount]*-1))))))>0
Or (Sum(IIf([TransType]="uc",[Amount],IIf([TransType]="CA",[Amount],
IIf([TransType]="RAC", [Amount],IIf([TransType]="UCBR",[Amount],[amount]*-1))))))<0)
just checks if the expression (sum(amount)) is either> 0or< 0and this should be equivalent with:
SUM(CASE WHEN [TransType] IN ('uc', 'CA', 'RAC', 'UCBR') THEN AMOUNT
ELSE AMOUNT*-1 END) <> 0

Related

Optimizing SQL Query speed

I am trying to optimize my SQL query below as I am using a very old RDMS called firebird. I tried rearranging the items in my where clause and removing the order by statement but the query still seems to take forever to run. Unfortunately firebird doesn't support Explain Execution Plan Functionalities and therefore I cannot identify the code that is holding up the query.
select T.veh_reg_no,T.CON_NO, sum(T.pos_gpsunlock) as SUM_GPS_UNLOCK,
count(T.pos_gpsunlock) as SUM_REPORTS, contract.con_name
from
(
select veh_reg_no,CON_NO,
case when pos_gpsunlock = upper('T') then 1 else 0 end as pos_gpsunlock
from vehpos
where veh_reg_no in
( select regno
from fleetvehicle
where fleetno in (97)
) --DS5
and pos_timestamp > '2022-07-01'
and pos_timestamp < '2022-08-01'
) T
join contract on T.con_no = contract.con_no
group by T.veh_reg_no, T.con_no,contract.con_name
order by SUM_GPS_UNLOCK desc;
If anyone can help it would be greatly appreciated.
I'd either comment out some of the sub-queries or remove a join or aggregation and see if that improves it. Once you find the offending code maybe you can move it or re-write it. I know nothing of Firebird but I'd approach that query with the below code, wrapping the aggregation outside of the joins and removing the "Where in" clause.
If nothing works can you create an aggregation table or pre-filtered table and use that?
select
x.*
,sum(case when x.pos_gpsunlock = upper('T') then 1 else 0 end) as SUM_GPS_UNLOCK
,count(*) as SUM_REPORTS
FROM (
select
a.veh_reg_no
,a.pos_gpsunlock
,a.CON_NO
,c.con_name
FROM vehpos a
JOIN fleetvehicle b on a.veg_reg_no = b.reg_no and b.fleetno = 97 and b.pos_timestamp between '222-07-01' and '2022-08-01'
JOIN contract c on a.con_no = contract.con_no
) x
Group By....
This might help by converting subqueries to joins and reducing nesting. Also an = instead of IN() operation.
select vp.veh_reg_no,vp.con_no,c.con_name,
count(*) as SUM_REPORTS,
sum(case when pos_gpsunlock = upper('T') then 1 else 0 end) as SUM_GPS_UNLOCK
from vehpos vp
inner join fleetvehicle fv on fv.fleetno = 97 and fv.regno = vp.veh_reg_no
inner join contract c on vp.con_no = c.con_no
where vp.pos_timestamp >= '2022-07-01'
and vp.pos_timestamp < '2022-08-01'
group by vp.veh_reg_no, vp.con_no, c.con_name

Case When + IN combination

I'm a bit stuck in my coding here... I have this extense and complex code, but I'm actually failling by the end of it. I'm getting the SQL Error [42804]: ERROR: argument of CASE/WHEN must be type boolean, not type character varying
The thing, is: when "bairro" matches a row from "SUB_COUNTRY_DB", get psd.name, else get z.name. Any tips on how I could accomplish this?
select distinct
aa.mes,
--aa.modalidade,
--to_date(aa.created_date, 'yyyy-mm-dd') data_captacao,
ucl.ja_comprou_lf as comprou_lf,
case when bairro in (select sub_country from sub_country_DB)
then psd.name
else z.name
end loja,
count (distinct aa.customer_uid) qtde_socios,
count (distinct aa.assinatura_uid) qtde_assinaturas
from assinaturas_ativas aa
left join ultima_compra_loja_fisica ucl on (aa.customer_uid = ucl.customer_uid
and aa.mes = ucl.mes)
left join zip_code z on (aa.customer_uid = z.customer_uid
and aa.mes = z.mes)
left join SUB_COUNTRY_DB psd
on (psd.district = aa.bairro)
group by 1,2,3--,4
Try variants like:
moving condition to an inner query
CASE WHEN EXISTS (SELECT DISTINCT sub_country FROM sub_country_DB WHERE sub_country = barrio)
ANY (PostgreSQL only)
CASE WHEN bairro = ANY(ARRAY_AGG(select sub_country from sub_country_DB))

Arithmetic overflow error converting varchar to data type numeric CASE statement

I am trying to write a query that returns an "Estimated Annual Value", and for this, I am using a Case statement. There are two inner joins involved in the query.
So, the query and gives me result when I am running this piece:
select Users.Id, Name, PhoneNumber, Email, Currency, count(*) as TotalOrders, sum(TotalCustomerAmount) as TotalOrderValue, avg(TotalCustomerAmount) as AverageOrderValue, TsCreate as RegistrationDate, max(TsOrderPlaced) as LastOrderDate, min(TsOrderPlaced) as FirstOrderDate,
CASE
When PromotionsEnabled = 0 then 'Y'
When PromotionsEnabled = 1 then 'n'
else 'undefined'
end as Promotions,
/*CASE
When ((DATEDIFF(day, max(TsOrderPlaced), min(TsOrderPlaced)) >= 6) AND (count(*) > 3)) then ((sum(TotalCustomerAmount)/(DATEDIFF(day, max(TsOrderPlaced), min(TsOrderPlaced))))*365)
Else '-'
end as EstimatedAnnualValue*/
from AspNetUsers with (nolock)
inner join Orders with (nolock) on Orders.UserId = AspNetUsers.Id and Orders.WhiteLabelConfigId = #WhiteLabelConfigId
and Orders.OrderState in (2,3,4,12)
inner join UserWhiteLabelConfigs with (nolock) on UserWhiteLabelConfigs.UserId = AspNetUsers.Id and Orders.WhiteLabelConfigId = #WhiteLabelConfigId
where AspNetUsers.Discriminator = 'ApplicationUser'
group by Users.Id, Name, Number, Currency, Email, TsCreate, PromotionsEnabled
But the problem comes when I am running this with the second CSAE statement, is it because I cannot use the aggregate function before GROUP BY? I am also thinking of using a Subquery
Looking fr some help!!
You need to use aggregation functions. For instance, if you want 'Y' only when all values are 0 or NULL:
(case when max(PromotionsEnabled) = 0 then 'Y'
when max(PromotionsEnabled) = 1 then 'N'
else 'undefined'
end) as Promotions,
I'm not sure if this is the logic you want (because that detail is not in the question). However, this shows that you can use aggregation functions in a case expression.

SQL Server CASE statement with subquery in then

I have the case statement below but despite it having the values that should trigger the case's, I am still getting nulls. Any obvious errors?
SELECT
*,
(CASE
WHEN topicname = 'TPOSTAL_CODE'
THEN (SELECT LTRIM(RTRIM(ALS_C)) AS LocationCode
FROM ODS.TBUS_LOC
WHERE cci.columna = ods.TBUS_LOC.BUS_LOC_I)
WHEN topicname = 'TBUSINESS_SITE'
THEN (SELECT LTRIM(RTRIM(B.ALS_C)) AS LocationCode
FROM ODS.TBUSINESS_SITE A
INNER JOIN ODS.TBUS_LOC B ON A.BUS_LOC_ID = B.BUS_LOC_I
WHERE cci.columna = A.BUS_LOC_ID)
END) AS Code
FROM
[XREF].[tablea] CCI
CCIEntityName with a distinct
It could be that topicname contains spaces either at the beginning or the end. These may not be readily visible to the eye. You might try
CASE WHEN ltrim(rtrim(topicname)) = 'TPOSTAL_CODE'
and see if that makes a difference.

ORA-00934: group function is not allowed here when adding case when

I have a piece of code which runs fine. However, when i am introducing a "case when" statement in the select clause, I get the "group function is not allowed here" error and I cannot fix it (the issue relates to the last Group by function in my code)
Any idea why (don't be put off by the code, it is 3 joins together, apparently the issue is caused by the last Group By statement) ?
Thank you!
SELECT
Trans_Table.MTAGRE01_NO
, (case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then (SUM(Trans_Table.MTTRANS01_VALUENCU)*-1)
else SUM(Trans_Table.MTTRANS01_VALUENCU) END) AS MTTRANS01_VALUENCU
FROM MTTRANS01 Trans_Table
INNER JOIN RUTRANTYPE01 Trans_Type
ON Trans_Type.RUTRANTYPE01_CODE = Trans_Table.RUTRANTYPE01_CODE
LEFT JOIN(
SELECT
MTAGRE01_NO
,CASE WHEN SRAGRESTAT01_CODE = 'COLL' THEN MTAGRE01_AGRESTATDATE END AS Date_Fr
from MTAGRE01
where CASE WHEN SRAGRESTAT01_CODE = 'COLL' THEN MTAGRE01_AGRESTATDATE END is not null
) F_Date
ON F_Date.MTAGRE01_NO = Trans_Table.MTAGRE01_NO
LEFT JOIN(
SELECT
Trans_Table.MTAGRE01_NO
FROM MTTRANS01 Trans_Table
INNER JOIN RUTRANTYPE01 Trans_Type ON Trans_Type.RUTRANTYPE01_CODE = Trans_Table.RUTRANTYPE01_CODE
GROUP BY
Trans_Table.MTAGRE01_NO, Trans_Type.RUTRANTYPE01_CODE, Trans_Type.RUTRANTYPE01_DESCRIPTION
) Cash
ON Cash.MTAGRE01_NO = Trans_Table.MTAGRE01_NO
where Trans_Type.SRPROCTYPE01_CODE in ('C','D')
and Trans_Table.MTTRANS01_VALUEDATE >= F_Date.Date_Fr
GROUP BY
Trans_Table.MTAGRE01_NO
, (case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then (SUM(Trans_Table.MTTRANS01_VALUENCU)*-1)
else SUM(Trans_Table.MTTRANS01_VALUENCU) END);
I believe it's hung up on the sum inside the case statement. 2 routes to correct that I can see, likely alot more:
This is a little hacky, but it'll work and give results fast. Change your case:
SELECT
Trans_Table.MTAGRE01_NO
, (case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then ((Trans_Table.MTTRANS01_VALUENCU)*-1)
else (Trans_Table.MTTRANS01_VALUENCU) END) AS MTTRANS01_VALUENCU
Remove the case from the group by.
Now call your entire query a sub query
Select MTAGRE01_NO, sum(MTTRANS01_VALUENCU)
(your entire query)a
You other option that takes a bit more work...in your initial from statement:
MTTRANS01 Trans_Table
Change that to a subquery that joins to the trans table and returns
case when Cash. MTAGRE01_NO = Trans_Table. MTAGRE01_NO
then ((Trans_Table.MTTRANS01_VALUENCU)*-1)
else (Trans_Table.MTTRANS01_VALUENCU) END as MTAGRE01_NO
Then join to that subquery and do a simple sum in your main query.
Hopefully that all makes sense, ask questions if you need clarifications