SQL query gives Incorrect syntax near ')' - use of CAST in INNER JOIN - sql-server

I get the error Incorrect syntax near ')' from the following SQL query:
SELECT
"GLPOST"."ACCTID",
"GLPOST"."FISCALYR",
"GLPOST"."FISCALPERD",
"GLPOST"."SRCELEDGER",
"GLPOST"."JRNLDATE",
"GLPOST"."BATCHNBR",
"GLPOST"."ENTRYNBR",
"GLPOST"."JNLDTLDESC",
"GLPOST"."JNLDTLREF",
"GLPOST"."TRANSAMT",
"APIBC"."POSTSEQNBR",
"APIBC"."CNTBTCH"
FROM ("MHLDAT"."dbo"."GLPOST" "GLPOST"
INNER JOIN "MHLDAT"."dbo"."GLJEH" "GLJEH"
ON (("GLPOST"."DRILSRCTY"="GLJEH"."DRILSRCTY")
AND ("GLPOST"."DRILLDWNLK"="GLJEH"."DRILLDWNLK")
AND "GLPOST"."DRILAPP"="GLJEH"."DRILAPP")))
INNER JOIN "MHLDAT"."dbo"."APIBC" "APIBC"
ON "APIBC"."POSTSEQNBR" = (CAST ("SUBSTRING" (CAST ("GLPOST"."DRILLDWNLK" AS "CHAR"(18)),3,CAST ("LEFT" (CAST ("GLPOST"."DRILLDWNLK" AS "CHAR"(18)),1) AS "INT" )) AS "INT" ))
WHERE
"GLPOST"."SRCELEDGER"=N'AP' AND "GLPOST"."FISCALYR"=N'2021' AND "GLPOST"."FISCALPERD"=N'01' AND "GLJEH"."ERRBATCH"=0
Any suggestions to resolve please?

SELECT
GLPOST.ACCTID,
GLPOST.FISCALYR,
GLPOST.FISCALPERD,
GLPOST.SRCELEDGER,
GLPOST.JRNLDATE,
GLPOST.BATCHNBR,
GLPOST.ENTRYNBR,
GLPOST.JNLDTLDESC,
GLPOST.JNLDTLREF,
GLPOST.TRANSAMT,
APIBC.POSTSEQNBR,
APIBC.CNTBTCH
FROM MHLDAT.dbo.GLPOST
INNER JOIN MHLDAT.dbo.GLJEH
ON GLPOST.DRILSRCTY=GLJEH.DRILSRCTY
AND GLPOST.DRILLDWNLK=GLJEH.DRILLDWNLK
AND GLPOST.DRILAPP=GLJEH.DRILAPP
INNER JOIN MHLDAT.dbo.APIBC
ON APIBC.POSTSEQNBR = CAST(SUBSTRING(CAST(GLPOST.DRILLDWNLK AS CHAR(18)),
3,
CAST(LEFT(CAST(GLPOST.DRILLDWNLK AS CHAR(18)),
1) AS INT)
) AS INT)
WHERE
GLPOST.SRCELEDGER = N'AP'
AND GLPOST.FISCALYR = N'2021'
AND GLPOST.FISCALPERD = N'01'
AND GLJEH.ERRBATCH = 0
You are using a lot of unnecessary parenthesis and double quoting, remove them (specially on the names of the functions SUBSTRING and LEFT). Remove the aliases (they are unnecessary because you use the same name as the table).
I have aligned your query so you can visually see where starts and ends every subexpression.

Related

Executing part of stored procedure based on condition

I am trying to load to a table based on load types - Full or Incremental that is being passed as parameter in stored procedure. I was able to try with substitution variable with one line of code previously, but the below code doesn't seem to work -
Stored procedure possible arguments:
LOAD_TYPE=FULL
LOAD_TYPE=INCR
var incr_condition = (load_type=='INCR')?"INNER JOIN temp_table"
with temp_table(
select data
from table a
where dt between 01-01-2019 and 09-09-2020
)
select *
from table b
${incr_condition} -- execute only if load_type=INCR
INNER JOIN TABLE C ON B.ID = C.ID
Is there any way to restrict the with clause to execute only if the load_type==INCR? Please advice.
I think the conditional operator (question mark) must have a false part in addition to the true part. Otherwise, it generates a syntax error when there's a semicolon ending the line. This example obviously doesn't run anything, but it will return the values assigned to the "out" variable, which would be run.
Since you're using a replacement variable ${incr_condition} be sure to use backticks to open and close your SQL string.
create or replace procedure foo(LOAD_TYP string)
returns string
language javascript
as
$$
var load_type = LOAD_TYP;
var incr_condition = (load_type === 'INCR') ? "INNER JOIN temp_table" : "";
var out = `
with temp_table(
select data
from table a
where dt between 01-01-2019 and 09-09-2020
)
select *
from table b
${incr_condition} -- execute only if load_type=INCR
INNER JOIN TABLE C ON B.ID = C.ID
`;
return out;
$$;
call foo('INCR'); --Adds the inner join
call foo('FULL'); --Does not add the inner join
I also recommend changing your comparison on strings from == to ===. For details on why, reference What is the correct way to check for string equality in JavaScript?.

Does SQL Server CASE expression not do short circuit?

Appropriate if somebody could help us to optimize below query
As per execution plane it seems the else part sub query is always executing, irrespective of conditions.
Won't CASE be short circuited? Why is it executing, even though it is not necessary?
IF OBJECT_ID('#Calculation') IS NOT NULL
DROP TABLE #Calculation;
SELECT
Result.IdDeckungsbeitrag,
Result.wert AS Wert,
REPLACE(#Formula, '<#PackagingCosts> ', Result.wert) AS Kalkulation
INTO
#Calculation
FROM
(SELECT
deck.IdDeckungsbeitrag,
CASE
WHEN lp.ID_VERPACKUNG_2 IS NULL
AND lp.ID_VERPACKUNG_3 IS NULL
THEN vg.VERPACKUNGSKOSTEN_PRO_EINHEIT * deck.Menge
ELSE
(
SELECT SUM(temp.me) * vg.VERPACKUNGSKOSTEN_PRO_EINHEIT
FROM
(
SELECT SUM(gv.MENGE) AS me
FROM dbo.KUNDENRECHNUNG_POSITION krp
LEFT JOIN dbo.LIEFERSCHEIN_POSITION lp
ON lp.ID_LIEFERSCHEIN_POSITION = krp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.GEBINDE_VERLADEN gv
ON gv.ID_LIEFERSCHEIN_POSITION = lp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.MATERIAL_BESTAND mb
ON mb.ID_MATERIAL_BESTAND = gv.ID_MATERIAL_BESTAND
LEFT JOIN dbo.MATERIAL_GEBINDE mg
ON mg.ID_MATERIAL_BESTAND = mg.ID_MATERIAL_BESTAND
WHERE mg.CHARGE_NUMMER = deck.Charge
GROUP BY mg.ID_VERPACKUNG
) temp
)
END AS wert
FROM #DeckungsbeitragCalculationPositions_TVP deck
LEFT JOIN dbo.KUNDENRECHNUNG_POSITION krp
ON krp.ID_KUNDENRECHNUNG_POSITION = deck.IdDeckungsbeitrag
LEFT JOIN dbo.LIEFERSCHEIN_POSITION lp
ON lp.ID_LIEFERSCHEIN_POSITION = krp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.VERPACKUNG vg
ON vg.ID_VERPACKUNG = lp.ID_VERPACKUNG_1
WHERE deck.IdMandant = #Id_Mandant
) Result;
Don't think of it as short-circuit or not. That's a procedural code mindset rather than a set-based mindset.
In SQL, the actual "execution" happens in the realm of table or index scans and seeks, hash matches, sorts, and the like. Pull data from different tables into a working set that will eventually produce the desired relational result.
Not seeing any real or projected execution plan, in this case (no pun intended), I suspect the query optimizer decided it was most efficient to first produce this result set in memory:
SELECT mg.ID_VERPACKUNG, mg.CHARGE_NUMMER, SUM(gv.MENGE) AS me
FROM dbo.KUNDENRECHNUNG_POSITION krp
LEFT JOIN dbo.LIEFERSCHEIN_POSITION lp
ON lp.ID_LIEFERSCHEIN_POSITION = krp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.GEBINDE_VERLADEN gv
ON gv.ID_LIEFERSCHEIN_POSITION = lp.ID_LIEFERSCHEIN_POSITION
LEFT JOIN dbo.MATERIAL_BESTAND mb
ON mb.ID_MATERIAL_BESTAND = gv.ID_MATERIAL_BESTAND
LEFT JOIN dbo.MATERIAL_GEBINDE mg
ON mg.ID_MATERIAL_BESTAND = mg.ID_MATERIAL_BESTAND
GROUP BY mg.ID_VERPACKUNG, mg.CHARGE_NUMMER
This is the subquery from the ELSE clause, minus the WHERE clause conditions and with additional info added to the SELECT to make the match more effective. If the query optimizer can't be confident of meeting the WHEN clause a high percentage of the time, it might believe producing this larger ELSE set once to match against as needed is more efficient. Put another way, if it thinks it will have to run that subquery a lot anyway, it may try to pre-load it for all possible data.
We don't know enough about your database to suggest real solutions, but indexing around the ID_VERPACKUNG_2, ID_VERPACKUNG_3, and CHARGE_NUMMER fields might help. You might also be able to use a CTE, temp table, or table variable to help Sql Server to a better job of caching this data just once.
If the conditions of where are not met then the else will become active. If this is always the case then you would expect the following to return no rows:
select *
FROM #DeckungsbeitragCalculationPositions_TVP deck
LEFT JOIN dbo.KUNDENRECHNUNG_POSITION krp ON krp.ID_KUNDENRECHNUNG_POSITION = deck.IdDeckungsbeitrag
LEFT JOIN dbo.LIEFERSCHEIN_POSITION lp ON lp.ID_LIEFERSCHEIN_POSITION = krp.ID_LIEFERSCHEIN_POSITION
WHERE lp.ID_VERPACKUNG_2 IS NULL
AND lp.ID_VERPACKUNG_3 IS NULL

Subquery returned more than 1 value causing query to fail

I'm stuck with this query. i want to show a field called "Executive" that must say "sin asignar" if there's no match when joining on the table 'prospectousuario', and if it exist it must say the first and the last name of the executive. But it returns the following error:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an exp
The query is:
select p.IDCANCAP,
p.CEDULA,
p.NOMBRES,
p.APELLIDOS,
p.CELULAR,
p.CASA,
p.CORREO,
p.ESTABLECIMIENTO,
c.DESCRIPCION,
(select case when
p.CEDULA = pu.IDPROSPECTO and pu.IDUSUARIO = u.CEDULA
then u.NOMBRES+' '+u.APELLIDOS else 'Sin asignar'
end from usuario as u, PROSPECTOUSUARIO as pu) as Ejecutivo,
p.FECHA_CREAC
from PROSPECTO p, CANALCAPTACION c
where p.IDCANCAP = c.IDCANAL
Boy this is a guess, based on your SQL and a lot of reading between the lines... but give it a try:
select p.IDCANCAP, p.CEDULA, p.NOMBRES,
p.APELLIDOS, p.CELULAR,p.CASA, p.CORREO,
p.ESTABLECIMIENTO, c.DESCRIPCION, p.FECHA_CREAC,
case when exists
(Select * from PROSPECTOUSUARIO
Where IDPROSPECTO = p.CEDULA)
then u.NOMBRES+' '+ u.APELLIDOS
else 'Sin asignar' end Ejecutivo
from PROSPECTO p
join CANALCAPTACION c on c.IDCANAL = p.IDCANCAP
join usuario u on u.CEDULA = p.CEDULA
Just as the error message says, your one and only subquery
(select case when
p.CEDULA = pu.IDPROSPECTO and pu.IDUSUARIO = u.CEDULA
then u.NOMBRES+' '+u.APELLIDOS else 'Sin asignar'
end from usuario as u, PROSPECTOUSUARIO as pu)
returns more than 1 row, which is not allowed when used as an expression inside the SELECT. In fact, it appears that the u and pu tables are not joined against any other tables in any meaningful way.
To fix, you must join the tables. In fact, you don't even need a subquery for what you're trying to do - move all tables to the FROM section and join them properly, whether inner or outer. Unfortunately, I don't know which fields they should be joined on, so I can't help there without more information or wild guessing.

An expression of non-boolean type specified in a context where a condition is expected, near 'end'. error

select *
from DBNAME.dbo.Shell_V36 V
inner join
DBNAME.DBO.Promo P
on
Case
when
(V.Product = P.From_Product_Code)
And (V.cur_date >= P.Promo_end_date)
or (V.cur_date <= P.Promo_start_date)
then (P.To_Product_Code)
else(P.From_Product_Code)
end
i am getting "An expression of non-boolean type specified in a context where a condition is expected, near 'end'." can any one help me out please.
You have to provide the field from Shell_V36 table used in the ON clause of the JOIN operation:
select *
from DBNAME.dbo.Shell_V36 V
inner join DBNAME.DBO.Promo P
on Case when
(V.Product = P.From_Product_Code) And
(V.cur_date >= P.Promo_end_date)
or
(V.cur_date <= P.Promo_start_date)
then (P.To_Product_Code)
else (P.From_Product_Code)
End = V.code -- presumably code field should be used

How to convert access query to sql server query string?

how to converse access query to sql server query string by programing?
example for access query string
SELECT dbo_VNMST.VISITDATE, dbo_VNTREAT.TREATMENTCODE, dbo_VNMST.HN, dbo_VNMST.VN, dbo_VNTREAT_1.TREATMENTCODE, Count(dbo_VNMST.HN) AS CountOfHN, dbo_PATIENT_NAME.SUFFIX, Mid([firstname],2) AS FIRSTNAME1, Mid([lastname],2) AS LASTNAME1, (FIRSTNAME1+' '+LASTNAME1) AS FULLNAME
FROM (((dbo_VNMST INNER JOIN dbo_VNTREAT ON (dbo_VNMST.VISITDATE = dbo_VNTREAT.VISITDATE) AND (dbo_VNMST.VN = dbo_VNTREAT.VN)) INNER JOIN dbo_VNPRES ON (dbo_VNMST.VISITDATE = dbo_VNPRES.VISITDATE) AND (dbo_VNMST.VN = dbo_VNPRES.VN)) INNER JOIN dbo_VNTREAT AS dbo_VNTREAT_1 ON (dbo_VNMST.VISITDATE = dbo_VNTREAT_1.VISITDATE) AND (dbo_VNMST.VN = dbo_VNTREAT_1.VN)) INNER JOIN dbo_PATIENT_NAME ON dbo_VNMST.HN = dbo_PATIENT_NAME.HN
GROUP BY dbo_VNMST.VISITDATE, dbo_VNTREAT.TREATMENTCODE, dbo_VNMST.HN, dbo_VNMST.VN, dbo_VNTREAT_1.TREATMENTCODE, dbo_PATIENT_NAME.SUFFIX, Mid([firstname],2), Mid([lastname],2)
HAVING (((dbo_VNMST.VISITDATE) Between #9/1/1466# And #9/14/1466#) AND ((dbo_VNTREAT.TREATMENTCODE)="3964") AND ((dbo_VNTREAT_1.TREATMENTCODE)="92H") AND ((dbo_PATIENT_NAME.SUFFIX)=0));
In addition to what Kane posted, you'll also need to replace the underscore ("_") between dbo and the table name with a period ("."), e.g.:
SELECT dbo_VNMST.VISITDATE
will become
SELECT dbo.VNMST.VISITDATE
You'll need to use the SUBSTRING function instead of the MID function, replace double quotes with a single quote and remove the hash (#) identifier for your BETWEEN statement.

Resources