Calculating Margin from Two Tables SQL - sql

So I am running into an issue that I have isolated to part of the WHERE statement and I can't figure it out. I am calculating margin for an item based on the cost and price tables associated with it. It works fine if I want to limit it to items whose list price is below 17%, but if I want to check the other price tiers, e.g. pricing if a customer buys +100 units, I get an ODBC error. This is my code that doesn't work:
strSQL = "SELECT IMFGR || ICOLOR || IPATT as Item, INAME as Description1, INAME2 as Description2, IPRCCD as PClass, ICSTCD as CClass, " _
& "c.TLASTC as Cost, p.$LIST as List, ((p.$LIST-c.TLASTC)/p.$LIST) as GPM, p.$P2 as Price2, ((p.$P2-c.TLASTC)/p.$P2) as GPM2, " _
& "p.$P3 as Price3, ((p.$P3-c.TLASTC)/p.$P3) as GPM3, p.$P4 as Price4, ((p.$P4-c.TLASTC)/p.$P4) as GPM4, p.$P5 as Price5, ((p.$P5-c.TLASTC)/p.$P5) as GPM5, " _
& "p.$P6 as Price6, ((p.$P6-c.TLASTC)/p.$P6) as GPM6, p.$P7 as Price7, ((p.$P7-c.TLASTC)/p.$P7) as GPM7, p.$P8 as Price8, ((p.$P8-c.TLASTC)/p.$P8) as GPM8, " _
& "p.$P9 as Price9, ((p.$P9-c.TLASTC)/p.$P9) as GPM9, p.$P10 as Price10, ((p.$P10-c.TLASTC)/p.$P10) as GPM10, p.$P11 as Price11, ((p.$P11-c.TLASTC)/p.$P11) as GPM11, " _
& "p.$P12 as Price12, ((p.$P12-c.TLASTC)/p.$P12) as GPM12 " _
& "FROM ITEM i " _
& "LEFT JOIN COST c " _
& "ON i.ICSTCD = c.TCSTCD " _
& "LEFT JOIN PRICE p " _
& "ON i.IPRCCD = p.$PRCCD " _
& "WHERE (IPRCCD != '') AND (p.$LIST# = 'LP') AND (IPOL1 != 'DI' AND IPOL2 != 'DI' AND IPOL3 != 'DI') AND (IPOL1 != 'BR' AND IPOL2 != 'BR' AND IPOL3 != 'BR') AND (IMFGR = '" & man & "') AND " _
& "((ICCTR != 'ZDS') AND (IPRODL != 'XXX')) AND " _
& "((p.$LIST-c.TLASTC)/p.$LIST) <= '" & margin & "' OR ((p.$P2-c.TLASTC)/p.$P2) <= '" & margin & "' " _
& "ORDER BY IMFGR"
The OR in the second to last line generates the error. If I change it to AND, it runs but then it looks for both statements to be true. I want to return a result if any of the margins are below a certain %. What am I doing wrong?
It isn't the p.$LIST# = 'LP' because the p.$p2, p.$p3, etc. are still in there with 'LP'

AND has precedence over OR. You need to wrap the OR clause in parens:
& "(((p.$LIST-c.TLASTC)/p.$LIST) <= '" & margin & "' OR ((p.$P2-c.TLASTC)/p.$P2) <= '" & margin & "') " _

Related

VB.Net: Escape singles quotes in query string that uses a variable with single quotes

A few of the records that my program is processing are creating a record in the log table that reads:
instruments: Incorrect syntax near 's'. Unclosed quotation mark after the character string ')))'.
The code uses an inline query that concatenates the value of a string variable to the WHERE clause in the SELECT and SubQueries.
Code:
SQL = "SELECT instrument_id, description, sub_category_of, meta_instrument" _
& " FROM instruments " _
& " WHERE (instrument_id IN " _
& " (SELECT instrument_id " _
& "FROM instruments " _
& "WHERE (description = '" & strn & "'))) " _
& "OR (instrument_id IN " _
& " (SELECT sub_category_of " _
& " FROM instruments AS instruments_1 " _
& " WHERE (description = '" & strn & "'))) " _
& "OR (instrument_id IN " _
& " (SELECT meta_instrument " _
& " FROM instruments AS instruments_1 " _
& " WHERE (description = '" & strn & "')))"
The actual query that gets executed against sql server:
SELECT instrument_id, description, sub_category_of, meta_instrument _
FROM instrument_ref
WHERE (instrument_id IN
(SELECT instrument_id
FROM instruments
WHERE (description = 'Women's Choir')))
OR (instrument_id IN
(SELECT sub_category_of
FROM instruments AS instruments_1
WHERE (description = 'Women's Choir')))
OR (instrument_id IN
(SELECT meta_instrument
FROM instruments AS instruments_1
WHERE (description = 'Women's Choir')))
I would like to ask for help in how the single quote can be handled so that this error can be corrected. Do I escape it in the 'strn' variable, or do I do it inside the inline query?
Thank you much.
As suggested, use parameters:
SQL = "SELECT instrument_id, description, sub_category_of, meta_instrument" _
& " FROM instruments " _
& " WHERE (instrument_id IN " _
& " (SELECT instrument_id " _
& "FROM instruments " _
& "WHERE (description = #description))) " _
& "OR (instrument_id IN " _
& " (SELECT sub_category_of " _
& " FROM instruments AS instruments_1 " ... etc
Then, when you construct the SqlCommand object with this SQL, use the command object's ".Parameters.AddWithValue()" method to add a parameter called "#description" and the appropriate value.
This, by the way, prevents someone from causing havoc by entering a description of "; drop table instruments;".

SQL query assistance needed with 'NOT'

I'm working out of VB6 with SQL SERVER 2012. I found myself in a pickle. Basically i have a query that works fine and pulls the necessary data in SQL SERVER, however, I'm having a difficult time translating it to vb6 SQL code. Here's a working query in SQL SERVER...
SELECT 'TotalSum' = SUM(Units)
FROM tblDetail
WHERE MemberID = '117'
AND CAST(SStartD AS DATETIME) >= '4/1/2016'
AND CAST(SStartD AS DATETIME) <= '4/7/2016'
AND Service = 166
AND [CODE] IN('1919')
AND NOT(InvoiceNo = '11880'
AND DtlNo = 2
)
AND NOT(InvoiceNo = '11880'
AND AdjNo = 2
);
So when I try to write it in my vb6 application i do something like
SELECT 'TotalSum' = SUM(Units)
FROM tblDetail
WHERE MemberID = '117'
AND CAST(SStartD AS DATETIME) >= '4/1/2016'
AND CAST(SStartD AS DATETIME) <= '4/7/2016'
AND Service = 166
AND [CODE] IN('1919')
AND (InvoiceNo <> '11880'
AND DtlNo <> 2
)
AND (InvoiceNo <> '11880'
AND AdjNo <> 2
);
However, this is not giving me the same results. Whats happening is in my last two clauses
( InvoiceNo <> '11880' AND DtlNo<> 2) AND (InvoiceNo <> '11880' AND AdjNo <> 2)
When I run them finally in SQL SERVER don't have paranthesis and its absolutely detrimental that the 2 seperate clauses are in paranthesis. Anyone know what I can do? I think my last resort might be to create a store procedure but i don't really want to do that.
EDIT:
g_SQL = "SELECT 'SUM' = SUM(Units) " & _
"FROM tblDetail WHERE " & _
"MemID = " & udtCDtl.Lines(udtCDtlIdx).MemID & " AND " & _
"CAST(SStartD As DateTime) >= '" & StartDate & "' AND " & _
"CAST(SStartD As DateTime) <= '" & DateAdd("d", -1, EndDate) & "' AND " & _
"Service = 166 AND " & _
"[CODE] IN (‘1919’)) And " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"DtlNo <> " & (InvoiceDtlRS! InvoiceDtlNo, "")) & " AND " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"AdjNo <> " & InvoiceDtlRS! InvoiceDtlNo)
Your translation of NOT(InvoiceNo = '11880' AND DtlNo = 2) to (InvoiceNo <> '11880' AND DtlNo <> 2) is incorrect.
In formal logic, !(A & B) is equivalent to (!A or !B), so it should be:
(InvoiceNo <> '11880' OR DtlNo <> 2)
This is why you're getting different results. However, why not use the original query? There's nothing in VB6 which would prevent it.
EDIT
g_SQL = "SELECT 'SUM' = SUM(Units) " & _
"FROM tblDetail WHERE " & _
"MemID = " & udtCDtl.Lines(udtCDtlIdx).MemID & " AND " & _
"CAST(SStartD As DateTime) >= '" & StartDate & "' AND " & _
"CAST(SStartD As DateTime) <= '" & DateAdd("d", -1, EndDate) & "' AND " & _
"Service = 166 AND " & _
"[CODE] IN (‘1919’)) And " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"DtlNo <> " & (InvoiceDtlRS! InvoiceDtlNo, "")) & " AND " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"AdjNo <> " & InvoiceDtlRS! InvoiceDtlNo)
You've got a ) in the wrong place twice. Also, the ) on the final live would be a syntax error I think. The last 5 lines should be:
"[CODE] IN (‘1919’) And " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"DtlNo <> " & (InvoiceDtlRS!InvoiceDtlNo, "") & " AND " & _
("InvoiceNo <> " & InvoiceDtlRS!InvoiceHdrNo & " OR " & _
"AdjNo <> " & InvoiceDtlRS!InvoiceDtlNo & ")"
This should work. I'm able to use SQL queries using NOT with ADODB in VB6.
g_SQL = "SELECT 'SUM' = SUM(Units) " & _
"FROM tblDetail WHERE " & _
"MemID = " & udtCDtl.Lines(udtCDtlIdx).MemID & " AND " & _
"CAST(SStartD As DateTime) >= '" & StartDate & "' AND " & _
"CAST(SStartD As DateTime) <= '" & DateAdd("d", -1, EndDate) & "' AND " & _
"Service = 166 AND " & _
"[CODE] IN ('1919')) And " & _
"NOT (InvoiceNo = " & InvoiceDtlRS!InvoiceHdrNo & " AND DtlNo = " & InvoiceDtlRS!InvoiceDtlNo & ") AND " & _
"NOT (InvoiceNo = " & InvoiceDtlRS!InvoiceHdrNo & " AND AdjNo = " & InvoiceDtlRS!InvoiceDtlNo & ")"
While Marc may have given you a query that works, Simon's question is still valid. The only reason your original query wouldn't work is because you munged the quotes. You'll notice that your parentheses by the reference to InvoiceNo are outside the quotes rather than inside them (there are other problems as well, from changing your original query, but I'll leave you to figure those out for yourself). That makes them not part of the quoted string, and instead part of the VB6 expression. Frankly, Marc isn't doing you any favors by providing an alternative SQL query that happens to have all the VB6 syntax correct, while yours does not. The real problem is that you haven't worked out how to put a SQL query into a quoted string carefully enough.
You can't afford that kind of carelessness if you want to be good at what you're doing. I don't say this to be offensive, but to get your attention. By adopting Marc's solution as the correct one, you haven't really solved your problem, because your problem is a mindset that doesn't think about anything except getting something to work. That mindset makes for the worst kind of programmer, the kind that writes terrible code (hundreds of lines of code where it could be done in 10, for example) that makes nightmares for people who have to maintain it later. Don't be one of those people. When you don't know why something isn't working, go to the trouble of figuring out why. You only have to do it once for each problem, and that mindset will stand you well as you continue to develop your skills.
Again, no disrespect intended. I'm just trying to get you to understand how to avoid getting in "pickles" like this one in future. Hopefully, the next time you post a question here, the "pickle" you're in will be more sophisticated. :)
EDIT: I guess I'm not making myself clear enough. The simple rule is that you need to enclose everything in the working SQL query in quoted strings, and replace the literal search values with references to text boxes, fields, or whatever. So:
sql = "SELECT 'TotalSum' = SUM(Units) " & _
"FROM tblDetail " & _
"WHERE MemberID = '" & myVariable & "' " & _
"AND CAST(SStartD AS DATETIME) >= '" & myVariable & "' " & _
"AND CAST(SStartD AS DATETIME) <= '" & myVariable & "' " & _
"AND Service = 166 " & _
"AND [CODE] IN('1919') " & _
"AND NOT(InvoiceNo = '" & myVariable & "' " & _
"AND DtlNo = " & myVariable & _
")" & _
"AND NOT(InvoiceNo = '" & myVariable & "' " & _
"AND AdjNo = " & myVariable & _
");"
Where myVariable is whatever variable reference you want to replace your literal string with. Any examples you've given have errors in placement of double quotes, which is why you aren't getting the result you want, which is presumably a replication of your working SQL query. The reason Marc's works is not because he altered your original query (it doesn't look like he has, except to put it on less lines) but because he placed his quotation marks correctly. The reason your and simon's solutions don't work is because neither of you have. Going back to your original post, the reason that the parentheses fail to show is because you haven't enclosed them in quotes. Marc has.

VBA SQL Join Query

I am having troubles with a VBA SQL JOIN. I Keep Getting A "Join Expression Not Supported" Error. The Following Code Works In The Query Design View but seems to throw an error when in vba.
Dim Rs As DAO.RecordSet
Set Rs = CurrentDb.OpenRecordset( _
"SELECT Schools.ID, Schools.[School Name],Schools.Address, Schools.Postcode, Schools.[Principal name], " & _
"Schools.[E-Mail], Schools.Phone, Schools.Region, Schools.JTHE, Schools.[Social Status], Events.Program " & _
"FROM Schools INNER JOIN Events ON Schools.ID = Events.School WHERE ((Schools.Region = '" & RegionOne & _
"' Or Schools.Region = '" & RegionTwo "' Or Schools.Region = '" & RegionThree "' Or Schools.Region = '" & _
RegionFour "') AND (Schools.JTHE = " & JTHE1 & " Or Schools.JTHE = " & JTHE2 ") AND (Schools.[Social Status] = '" & _
StatusBox.Value "') AND (Events.Program = '" & ProgramBox.Value & "'));")
This Similar Query Works
Set Rs = CurrentDb.OpenRecordset("SELECT * FROM Schools WHERE " & _
"(((Schools.Region)='" & RegionOne & _
"' Or (Schools.Region)='" & RegionTwo & _
"' Or (Schools.Region)='" & RegionThree & _
"' Or (Schools.Region)='" & RegionFour & _
"') AND ((Schools.[Social Status])='" & StatusBox.Value & _
"') AND ((Schools.JTHE)=" & JTHE1 & " Or (Schools.JTHE)=" & JTHE2 & "));")
Any help would be greatly appreciated.
I'm not entirely sure why is that. It is hard to spot error when your doing it on VBA, unlike if your in an actual SQL Management studio where you can spot the lines that errors out. Nonetheless, you may try this:
Set Rs = CurrentDb.OpenRecordset( _
"SELECT Schools.ID, Schools.[School Name], Schools.Address, " & _
"Schools.Postcode, Schools.[Principal name], Schools.[E-Mail], " & _
"Schools.Phone, Schools.Region, Schools.JTHE, Schools.[Social Status], " & _
"Events.Program " & _
"FROM Schools " & _
"INNER JOIN Events " & _
"ON Schools.ID = Events.School " & _
"WHERE Schools.Region IN (" & _
"'" & RegionOne & "'," & _
"'" & RegionTwo & "'," & _
"'" & RegionThree & "'," & _
"'" & RegionFour & "') " & _
"AND Schools.JTHE IN (" & JTHE1 & ", " & JTHE2 & ") " & _
"AND Schools.[Social Status]='" & StatusBox.Value & "' " & _
"AND Events.Program='" & ProgramBox.Value & "';")
I formatted it as such to give you the story of the query (and that is how I will write it in SQL). Not really a direct to the point answer to your question but I just simplified your OR statements and instead uses IN. You might get a:
Too many continuous line error
So adjust the concatenation of strings. I have not tested this of course (although it compiles) but my goal is to give you idea on a possible way to do it. HTH.

Query - Error assigning value to variable in VB

I have the following code to query in VB6:
SQL = " if object_id('tempdb..#MovSeq','U') is not null drop table #MovSeq;" & _
" declare #Data_Inicio datetime, #Data_Fim datetime; set dateformat dmy; set #Data_Inicio = DataInicio; set #Data_Fim = DataFinal; set #Data_Fim = DateAdd(day, +1, #Data_Fim); " & _
" with Mov as ( SELECT EI.Cod_Empresa, EI.Cod_Estoque, EI.Cod_Produto, 'E' as Tipo_Mov, E.Dta_Entrada as Data_Mov, EI.id_Doc as NF, EI.Qtde, EI.V_Unitario, EI.V_Total " & _
" from Entrada_Itens as EI inner join Entrada as E on EI.Cod_Empresa=E.Cod_Empresa and EI.id_Doc=E.id_Doc " & _
" where E.Dta_Entrada >= #Data_Inicio and EI.Cod_Empresa='" & Sys.Empresa & "' and EI.Cod_Estoque='" & dcEstoque.BoundText & "' and EI.Cod_Produto='" & dtProdutos.BoundText & "' " & _
" Union " & _
" SELECT SI.Cod_Empresa, SI.Cod_Estoque, SI.Cod_Produto, 'S', S.Dta_Entrada , SI.id_Doc, -SI.Qtde, SI.V_Unitario, SI.V_Total " & _
" from Saida_Itens as SI inner join Saida as S on SI.Cod_Empresa=S.Cod_Empresa and SI.id_Doc=S.id_Doc " & _
" where S.Dta_Entrada >= #Data_Inicio and SI.Cod_Empresa='" & Sys.Empresa & "' and SI.Cod_Estoque='" & dcEstoque.BoundText & "' and SI.Cod_Produto='" & dtProdutos.BoundText & "' " & _
" Union " & _
" SELECT Cod_Empresa, Cod_Estoque, Cod_Produto, 'A', #Data_Inicio, null, null, null, null " & _
" From Estoque " & _
" where Cod_Empresa='" & Sys.Empresa & "' and Cod_Estoque='" & dcEstoque.BoundText & "' and Cod_Produto='" & dtProdutos.BoundText & "') " & _
" SELECT *, Seq= row_number() over (partition by Cod_Empresa, Cod_Estoque, Cod_Produto order by Data_Mov desc, Tipo_Mov desc) into #MovSeq from Mov; " & _
" create unique clustered index IndMovSeq on #MovSeq (Cod_Empresa, Cod_Estoque, Cod_Produto, Seq); " & _
" SELECT M.Cod_Empresa, M.Cod_Estoque, M.Cod_Produto, P.Descricao," & _
" Estoque= case when M.Seq=1 then E.Qtde_Estoque else (E.Qtde_Estoque - (SELECT sum(Mi.Qtde) from #MovSeq as Mi " & _
" Where Mi.Cod_Empresa = M.Cod_Empresa And Mi.Cod_Estoque = M.Cod_Estoque And Mi.Cod_Produto = M.Cod_Produto and Mi.Seq < M.Seq)) end " & _
" from #MovSeq as M inner join " & _
" Estoque as E on M.Cod_Empresa=E.Cod_Empresa and M.Cod_Estoque=E.Cod_Estoque and M.Cod_Produto=E.Cod_Produto inner join " & _
" Produtos as P on M.Cod_Empresa=P.Cod_Empresa and M.Cod_Estoque=P.Cod_Estoque and M.Cod_Produto=P.Cod_Produto " & _
" where Data_Mov < #Data_Fim " & _
" order by M.Cod_Empresa, M.Cod_Estoque, M.Cod_Produto, Seq desc; " & _
" drop table #MovSeq;"
the error appears 'invalid columm name' when run showing DataInicio as a reason
I know the error is in the assignment of the variable. but how to solve.
Thanks for the help...
Your type of code is very prone to SQL Injection attacks...
Are you escaping the variable values correctly? A simple quote (') in one of the variables can change the SQL string completely...
You should consider using parameters to pass values instead of building SQL commands using string concatenation.

Filtering with Combo Boxes and SQL Using the MID Command

I have tried and tried to get this peice of code working but with no luck.
The code is supposed to pick products that have the same sections of product code as cmbsource.
Private Sub cmbSource_AfterUpdate()
Dim Worktop As String
If ProductType = 1 Then
Worktop = "SELECT [products/stock].[Product Code], [products/stock].Description, [products/stock].[Stock Level] FROM [products/stock] " & _
"WHERE Category = 'DPALRC' " & _
"AND Mid('[Product Code]',1,5) = Mid('" & Me.cmbSource.Value & "',1,5) " & _
"AND Mid('[Product Code]',9,6) = Mid('" & Me.cmbSource.Value & "',9,6) " & _
"ORDER BY [Product Code];"
Me.cmbResult.rowSource = Worktop
Me.cmbResult = vbNullString
End If
Any Ideas?
Thanks in advance,
Bob P
Just a wild guess here.
Worktop = "SELECT ps.[Product Code], ps.Description, ps.[Stock Level]" & vbCrLf & _
"FROM [products/stock] AS ps" & vbCrLf & _
"WHERE ps.Category = 'DPALRC'" & vbCrLf & _
"AND Mid([Product Code],1,5) = '" & Mid(Me.cmbSource,1,5) & "'" & vbCrLf & _
"AND Mid([Product Code],9,6) = '" & Mid(Me.cmbSource,9,6) & "'" & vbCrLf & _
"ORDER BY ps.[Product Code];"
Debug.Print Worktop
Go to the Immediate window (Ctrl+g) and copy the statement from there. Then create a new Access query, switch to SQL View, paste in the statement text, and run it.
If the code I suggested does not return the results you want, show us the actual SQL statement text and explain what is wrong with it.
Worktop = "SELECT [products/stock].[Product Code], [products/stock].Description, [products/stock].[Stock Level] FROM [products/stock] " & _
"WHERE Category = 'DPALRC' " & _
"AND Mid([Product Code],1,5) = Mid('" & Me.cmbSource.Value & "',1,5) " & _
"AND Mid([Product Code],9,6) = Mid('" & Me.cmbSource.Value & "',9,6) " & _
"ORDER BY [Product Code];"
This is my updated version, turns out the only error in the coding was having the single quotes around [Product Code].