SSIS Package with User Variable in Where Clause - sql-server

Simply put, I'm trying to take user input, store it in a variable, and then use that variable in a query.
First, I have a Script Task that opens a window with a simple input text box and a button. On click, the text gets put into a user variable and a message box pops up to display what is in the user variable. Clicking Ok on the message box closes both the message box and original window. This seems to work fine.
Next, I have an Execute SQL Task. Settings are as follows:
General
ResultSet = None
ConectionType = OLE DB
Connection = localhost.DB
SQLSourceType = Direct Input
SQLStatement = [SQL Code displayed below]
Parameter Mapping
Variable Name = User::VarName
Direction = Input
DataType = VARCHAR
Parameter Name = 0
Parameter Size = 65535
Result Set - N/A
Expressions - N/A
[SQL CODE]
if object_id('TEST.dbo.TEST','U') is not null
drop table TEST.dbo.TEST;
SELECT
coalesce(FSC.a, format(cast(SVY.b as int),'000')) as ab,
SVY.c,
PP.d,
SV1.e,
PP.f,
PP.g,
cast(PP.g as float) AS g,
SV1.h,
SV1.i,
SVY.j,
SVY.k,
format(cast(SVY.l as int), '00000') as l,
CAST(SVY.m AS float) AS m,
SVY.n,
SV1.o,
SVY.p,
cast(PID.q as float) as q,
cast(PID.r as float) as r,
cast(PID.s as float) as s,
cast(PID.t as float) as t,
PID.u as u,
PID.v as v,
PP.w,
CAL_B.x as x,
CAL_B.y as y,
CAL_B.z as z,
CAL_R.aa as aa,
CAL_R.bb as bb,
CAL_R.cc as cc
into TEST.dbo.TEST
FROM AAA.dbo.AAA PP
INNER JOIN BBB.dbo.BBB PPC
ON PP.x = PPC.x
AND cast(PP.x as date) = cast(PPC.x as date)
RIGHT OUTER JOIN CCC.dbo.CCC SVY
ON PPC.x = SVY.x
AND cast(PPC.x as date) = cast(SVY.x as date)
LEFT OUTER JOIN DDD.dbo.DDD FSC
ON SVY.x = FSC.x
AND cast(SVY.x as date) = cast(FSC.x as date)
LEFT OUTER JOIN EEE.dbo.EEE SV1
ON SVY.x = SV1.x
AND SVY.x = SV1.x
AND SVY.x = SV1.x
AND SVY.x = SV1.x
AND cast(SVY.x as date) = cast(SV1.x as date)
AND PPC.x = SV1.x
AND cast(PPC.x as date) = cast(SV1.x as date)
INNER JOIN FFF.dbo.FFF RLS
ON SV1.x = RLS.x
AND SV1.x = RLS.x
AND cast(SV1.x as date) = cast(RLS.x as date)
AND SVY.x = RLS.x
AND SVY.x = RLS.x
AND SVY.x = RLS.x
AND cast(SVY.x as date) = cast(RLS.x as date)
LEFT OUTER JOIN GGG.dbo.GGG PID
ON PP.x = PID.x
AND coalesce(FSC.x, format(cast(SVY.x as int),'000')) = PID.x
LEFT OUTER JOIN HHH.dbo.HHH CAL_B
ON cast('20' + SUBSTRING(RLS.x,4,2) + '-' + SUBSTRING(RLS.x,6,2) + '-' + SUBSTRING(RLS.x,8,2) as date) = CAL_B.x
AND CAL_B.x = 1
LEFT OUTER JOIN III.dbo.III CAL_R
ON cast('20' + SUBSTRING(RLS.x,4,2) + '-' + SUBSTRING(RLS.x,6,2) + '-' + SUBSTRING(RLS.x,8,2) as date) = CAL_R.x
AND CAL_R.x = 1
where
cast(SVY.x as date) = (select cast(max(x) as date) from JJJ.dbo.JJJ)
and
PP.x is not null
and
SVY.x in ( ? )
THE ISSUE: I run the package. Text input box opens. I put in my text, " 'CN05','CN06' " (without double quotes), I click OK. Box pops up showing me my input. I click OK. Workflow moves on to Execute SQL Task. In 1 second the task completes with a green check, no errors. I verify that TEST.dbo.TEST has been created but it is empty.
Now, if I run the above code in SSMS hardcoding the last bit [...SVY.x in ('CN05','CN06')], I pull back over 5 million records in about 4 minutes. I am stumped as to why this isn't working in SSIS. Any ideas out there?

In general, parameterized WHERE IN clauses don't play nice. They never work the way we think they should. Instead, you can use SSIS' version of dynamic SQL to achieve the same thing. Create a string variable to store the concatenation of your larger SQL statement with your user input. Then, wire your Execute SQL Task to use this variable.
For example, please create a new SSIS string variable called SqlStatement. In the properties window for the variable, open the expression builder window by clicking the ellipses. Use this expression builder to concatenate your SQL with the user input. Sample below ...
Be sure to set the EvaluateAsExpression property of the variable to True.
Lastly, change your Execute SQL Task over from Direct Input to Variable and select this variable as the source.
All set. Your Execute SQL Task should now be wired to use the dynamic SQL you built inside of the expression builder. Good luck!

Related

Iterate through a list using SQL While Loop

I have written a SQL query that joins two tables and calculates the difference between two variables. I want a while loop iterate through the code and do the procedure for a list of organizations numbers orgnr.
Use Intra;
drop table #Tabell1
go
select Månad = A.Manad, Intrastat = A.varde, Moms = B.vardeutf
into #Tabell1
From
IntrastatFsum A
join
Momsuppg B
on A.Orgnr = B.Orgnr
where A.Orgnr = 165564845492
AND A.Ar = 2017
AND B.Ar = A.AR
--AND A.Manad = 11
AND A.Manad = B.Manad
AND A.InfUtf = 'U'
order by A.Manad
select *, Differens = (Intrastat - Moms)/ Moms from #Tabell1
Where do I put the while loop and how should I write it? I don't have a lot of experience with SQL so any help is appreciated.
wasnt clear at all when posting this question was in a big hurry, so sorry guys for that. But what im trying to do is:
This code just runs trough some data, calculates the difference in % for a special company. Each month we get a list of companies that show high standard deviation for some variables. So we have to go through them and compare the reported value with the taxreturn. What im trying to do is write a code that compares the values for "Intra" which is the reported value and " Moms" which is reported tax value. That part i have already done what i need to do now is to insert a loop into the code that goes through a list instead where i have stored the orgnr for companies that show high std for some variables.I want it to keep a list of the companies where the difference between the reported values and taxreturn is high, so i can take an extra look at them. Because sometimes the taxreturn and reported value to ous is almost the same, so i try to remove the most obvious cases with automation
I don't think you need a loop in your query.
Try changing this where-clause:
where A.Orgnr = 165564845492
To this:
where A.Orgnr in (165564845492, 123, 456, 678)
just remove A.Orgnr = 165564845492 in where clause, there is no need of loop
Use Intra;
drop table #Tabell1
go
select Månad = A.Manad, Intrastat = A.varde,Moms = B.vardeutf
into #Tabell1
From
IntrastatFsum A
join
Momsuppg B
on A.Orgnr = B.Orgnr
where A.Ar = 2017
AND B.Ar = A.AR
--AND A.Manad = 11
AND A.Manad = B.Manad
AND A.InfUtf = 'U'
order by A.Manad
select *, Differens = (Intrastat - Moms)/ Moms from #Tabell1
Question is not clear (to me)
select Månad = A.Manad, Intrastat = A.varde, Moms = B.vardeutf
, Differens = (A.varde - B.vardeutf) / B.vardeutf
From
IntrastatFsum A
join
Momsuppg B
on A.Orgnr = B.Orgnr
AND A.Orgnr in (165564845492, ...)
AND A.Ar = 2017
AND A.Manad = B.Manad
AND A.InfUtf = 'U'
order by A.Manad

How to correctly set expression Query.CommandText in SSRS?

In my SSRS report builder I have an expression set for one of my dataset (name is dsTagAttributes). The query type is text.
This is the query expression
="select m.TagName, ta.descriptor, t.[State] from MasterTags m inner join TagAttributesClassic ta on m.ID = ta.TagID inner join TagStates t on t.ID = m.StateID where m.PIServerID = #ServerID and t.[State] = #State and m.MetaData1 = #Station " & Parameters!AndOr.Value & "m.MetaData2 = #Device"
The above query expression has a parameter which is concatenated in the select statement.
The parameter #AndOr data type is text, has a default value of "or", and parameter visibility is set to hidden (screen shot below). I have set this parameter because it will be used to dynamically change the dataset result from or to and during the report runtime.
But when I run the report, an exception is thrown saying,
What could go wrong in my query command text?
Any help is greatly appreciated.
You can run Profiler against Data Source to see the query.
I assume the problem is that you miss "'" before and after each varchar value (#State, #Station).
I wouldn't use that way to use OrAnd condition
You can modify TSQL like
...
AND
(m.MetaData2 = #Device AND #OrAnd = 'AND')
)
OR
(m.MetaData2 = #Device AND #OrAnd = 'OR')
Just make sure you place ')' and '(' correctly, depending on business logic.

how to for each loop on data table within another datatable

I have a web poll application that reads and processes orders from sql server back end and inserts into windss(jda).
the flow
1) I read all the orders from the sql server tables that is not processed
2) then I need to divide the orders into two sets
- set 1 orders with bundle kit( 1 order with several suborders)
- set 2 is just orders with no bundle kit
3) then after each order is processed I need to update the isprocessed sql field to 1
1) code for reading all orders
Frmmain.vb
dt = WebDatabase.GetAllOrdersFromDatabase()**'this method is below**
For Each drow In dt.Rows
If CDbl(WinDSSStoreNumber) = 123 Or CDbl(WinDSSStoreNumber) = 124 Then
' Store 123 and 124 = customer service - only orders with qualifying source codes
my question is:
the above for each checks if the store is 123 or 124 but now I want to implement another for each loop that reads all the InvoiceHeader_Id that the second field in the datatable and then check if it has a bundle kit or not if it does then process it and update the isprocessed field second last in the datatable else process the orders without any bundle kit and update isprocessed for those as well. please any help is generously appreciated, please ask me any questions in the below comment before marking my question down.
WebData.vb
Public Function GetAllOrdersFromDatabase() As DataTable
DrivePath = "C:\Users\somjething\Documents\files\somefiles\"
Dim ds As DataTable = Nothing
WinDSS.connectionString = ConfigurationManager.AppSettings("WinDSS_Connection").Replace("%DrivePath%", DrivePath)
ds = WinDSS.GetSysMst()
If ds.Rows.Count > 0 Then
WinDSSStoreNumber = ds.Rows(0)("store_no")
End If
Dim dt As New DataTable()
Dim conn As New SqlConnection(ConfigurationManager.AppSettings("WebData_Connection") & ConfigurationManager.AppSettings("WebDataSource"))
Dim cmd As SqlCommand
Dim da As New SqlDataAdapter
conn.Open()
cmd = conn.CreateCommand()
cmd.CommandType = CommandType.Text
cmd.CommandText= SELECT InvoiceDetail_Id, InvoiceHeader_Id, ActualFreightCharge, AmountCollected,
ChargedActualFreight, CollectedExternally, CollectedThroughAR, DateInvoiced, InvoiceNo,
InvoiceType, LineSubTotal, MasterInvoiceNo, OrderInvoiceKey, Reference1, TotalAmount,
TotalTax, isprocessed, storetoprocess
FROM dbo.InvoiceHeader
WHERE (isprocessed = 0) AND (storetoprocess = N'123')
da.SelectCommand = cmd
da.Fill(dt)
conn.Close()
Return dt
End Function
Additoinal info
This is the information given to me by my manager:
loop throught each below
SELECT InvoiceDetail_Id, InvoiceHeader_Id, ActualFreightCharge, AmountCollected,
ChargedActualFreight, CollectedExternally, CollectedThroughAR, DateInvoiced, InvoiceNo,
InvoiceType, LineSubTotal, MasterInvoiceNo, OrderInvoiceKey, Reference1, TotalAmount,
TotalTax, isprocessed, storetoprocess
FROM dbo.InvoiceHeader WHERE (isprocessed = 0) AND (storetoprocess = N'195')
Use the above InvoiceHeader_Id to loop throught all of the order information. Process each Bundle (Kit/)
SELECT InvoiceHeader_Id, LineDetails_Id, LineDetail_Id, OrderLine_Id, GiftFlag, [References],
GiftWrap, IsBundleParent, KitCode, KitQty, LevelOfService, LineSeqNo, LineType,
MaxLineStatus, MaxLineStatusDesc, MinLineStatus, MinLineStatusDesc, MinShipByDate,
OpenQty, OrderHeaderKey, OrderLineKey, OrderedQty, OriginalOrderedQty, OtherCharges,
OverallStatus, PipelineKey, PrimeLineNo, ReceivingNode, RemainingQty, ReqCancelDate,
ReqDeliveryDate,
ReqShipDate, SCAC, ScacAndService, ScacAndServiceKey, ShipNode, ShipToID, ShipToKey,
StatusQuantity, SubLineNo, SubstituteItemID, isprocessed
FROM dbo.OrderLine
WHERE (isprocessed = 0) AND (InvoiceHeader_Id = 13) AND (IsBundleParent = 'Y')
ORDER BY PrimeLineNo, SubLineNo
For each record in the above list query below and add as Zero (0) dollar amount. The cost is associated with the information above record (you may have to query tables to ge the values)
Get the OrderLineKey from the above record and query this below to get the associated sub items.
SELECT TOP (100) PERCENT dbo.BundleParentLine.InvoiceHeader_Id AS BPL_InvoiceHeader_Id,
dbo.BundleParentLine.LineDetails_Id AS BPL_LineDetails_Id, dbo.BundleParentLine.LineDetail_Id AS BPL_LineDetail_Id, dbo.BundleParentLine.OrderLine_Id AS BPL_OrderLine_Id, dbo.BundleParentLine.BundleParentLine_id, dbo.BundleParentLine.SubLineNo AS BPL_SubLineNo, dbo.BundleParentLine.PrimeLineNo AS BPL_PrimeLineNo, dbo.BundleParentLine.OrderLineKey AS BPL_OrderLineKey, dbo.OrderLine.*
FROM dbo.BundleParentLine INNER JOIN dbo.OrderLine ON dbo.BundleParentLine.OrderLine_Id = dbo.OrderLine.OrderLine_Id AND dbo.BundleParentLine.LineDetail_Id = dbo.OrderLine.LineDetail_Id AND dbo.BundleParentLine.LineDetails_Id = dbo.OrderLine.LineDetails_Id AND dbo.BundleParentLine.InvoiceHeader_Id = dbo.OrderLine.InvoiceHeader_Id
WHERE (dbo.BundleParentLine.OrderLineKey = N'76873264832') AND (dbo.BundleParentLine.InvoiceHeader_Id = 13) AND (dbo.BundleParentLine.LineDetails_Id = 6) AND (dbo.OrderLine.isprocessed = 0)
ORDER BY BPL_PrimeLineNo, BPL_SubLineNo
After Processed, set isprocessed = 1
Use the above InvoiceHeader_Id to loop throught all of the order information
SELECT InvoiceHeader_Id, LineDetails_Id, LineDetail_Id, OrderLine_Id, GiftFlag, [References],
GiftWrap, IsBundleParent, KitCode, KitQty, LevelOfService, LineSeqNo,
LineType,
MaxLineStatus, MaxLineStatusDesc, MinLineStatus, MinLineStatusDesc, MinShipByDate,
OpenQty, OrderHeaderKey, OrderLineKey, OrderedQty,
OriginalOrderedQty,
OtherCharges, OverallStatus, PipelineKey, PrimeLineNo, ReceivingNode, RemainingQty,
ReqCancelDate, ReqDeliveryDate, ReqShipDate, SCAC,
ScacAndService,
ScacAndServiceKey, ShipNode, ShipToID, ShipToKey, StatusQuantity,
SubLineNo, SubstituteItemID, isprocessed
FROM dbo.OrderLine
WHERE (isprocessed = 0) AND (InvoiceHeader_Id = 13) AND (IsBundleParent <> 'Y')
ORDER BY PrimeLineNo, SubLineNo
After Processed, set isprocessed = 1
This is not an answer but I want to pose this to prompt you for some clarification and it's not practical in the comments.
First, close visual studio and open SQL Server Management Studio and connect to the database
We'll build some select statements to get the data back and then we can think about an UPDATE statement
This first query you posted gives you the unprocessed headers for store 195 (straight from your post). I don't know if you want to do this for all stores or not. Paste it into SSMS and run it
SELECT H.*
FROM dbo.InvoiceHeader H
WHERE H.isprocessed = 0 AND H.storetoprocess = N'195'
Now, this second query gives you the unprocessed lines against that header that have IsBundleParent='Y'.
Look! No loops!
SELECT H.*, L.*
FROM dbo.InvoiceHeader H
INNER JOIN
dbo.OrderLine L
ON L.InvoiceHeader_Id = H.InvoiceHeader_Id
WHERE H.isprocessed = 0 AND H.storetoprocess = N'195'
AND L.isprocessed = 0 AND L.IsBundleParent = 'Y'
Then in your explanation you have For each record in the above list query below and add as Zero (0) dollar amount which makes no sense to me so perhaps you could clarify
Now we'll add the third query in which adds BundleParentLine (which does have inner joins in it already, but it's a pretty strange list of join fields)
SELECT H.*, L.*, BPL.*
FROM dbo.InvoiceHeader H
INNER JOIN
dbo.OrderLine L
ON L.InvoiceHeader_Id = H.InvoiceHeader_Id
INNER JOIN
dbo.BundleParentLine BPL
ON BPL.OrderLine_Id = L.OrderLine_Id
AND BPL.LineDetail_Id = L.LineDetail_Id
AND BPL.LineDetails_Id = L.LineDetails_Id
AND BPL.InvoiceHeader_Id = L.InvoiceHeader_Id
WHERE H.isprocessed = 0 AND H.storetoprocess = N'195'
AND L.isprocessed = 0 AND L.IsBundleParent = 'Y'
Then in your explanation you have After Processed, set isprocessed = 1, but what is 'processed' here? Is it just setting it to processed in the table?
To do that you just write an UPDATE statement. Here's one way to do that to update just the header (don't run it though until we understand what you're trying to do). Is the problem here that you want to set header and line to processed at the same time?
UPDATE InvoiceHeader
SET Processed = 1
WHERE isprocessed = 0 AND storetoprocess = N'195'
The fourth query you have seems to account for the IsBundleParent <> 'Y' case
Again, we need to know what add as Zero (0) dollar amount and processed means to go any further.

Converting T-SQL Left Join Subqueries to MS-Access

I need help in converting this T-SQL query to MS ACCESS. The error that I'm getting is JOIN expression not supported.
Update:
I can't add:
DDA ON TT.[Description] = DDA.AccountTypeDesc AND
H.AccountNumber = DDA.AccountNumber
But
DDA ON TT.[Description] = DDA.AccountTypeDesc
works. Is there a way to add the second condition?
T-SQL Query:
SELECT
*
FROM
(
SELECT
[PesoAmount] = CASE WHEN FE.IsoCode IS NULL THEN
LTRIM(STR(DFCF.CurrencyAmount, 20, 2))
ELSE
LTRIM(STR(DFCF.CurrencyAmount * FE.PhpConversionRate, 20, 2))
END,
DFCF.TransactionNumber,
DFCF.AccountNumber,
DFCF.CountryCd,
DFCF.TransactionTypeCd,
DFCF.Time,
DFCF.Date,
DFCF.TransactionStatusCd,
DFCF.TransactionCurrencyCd,
DFCF.BranchNumber,
DFCF.RemitterExtPartyCd,
DFCF.BeneficiaryExtPartyCd,
DFCF.PostedDate,
DFCF.AssociateNumber,
DFCF.ExecutingPartyNumber,
DFCF.CurrencyAmount,
DFCF.CurrencyAmountInTxnCcy,
DFCF.CurrencyAmountInAccountCcy,
DFCF.SecondaryAccountKey,
DFCF.RelatedInd,
DFCF.ThirdPartyInd,
DFCF.TransactionDescription,
DFCF.SecurityName,
DFCF.DealNumber
FROM
dbo.DesFactCashFlow DFCF (NOLOCK) LEFT JOIN
dbo.ForeignExchange FE (NOLOCK) ON DFCF.TransactionCurrencyCd = FE.IsoCode
)
H LEFT JOIN
dbo.Ctr C (NOLOCK) ON H.PesoAmount = C.PesoAmountFaceValueSumInsured AND
H.AccountNumber = C.AccountNumber AND
H.TransactionTypeCd = C.TransactionType LEFT JOIN
dbo.TransactionType TT (NOLOCK) ON H.TransactionTypeCd = TT.Code LEFT JOIN
(
SELECT
[AccountNumber] = DDA2.AccountNumber,
[AccountTypeDesc] = DDA2.AccountTypeDesc,
[LineOfBusinessName] = MAX(DDA2.LineOfBusinessName),
[AccountCurrencyCode] = MAX(DDA2.AccountCurrencyCode),
[AccountCurrencyName] = MAX(DDA2.AccountCurrencyName),
[AccountRegistrationTypeDesc] = MAX(DDA2.AccountRegistrationTypeDesc),
[AccountRegistrationName] = MAX(DDA2.AccountRegistrationName),
[AccountName] = MAX(DDA2.AccountName),
[AlternateName] = MAX(DDA2.AlternateName),
[AccountOpenDate] = MAX(DDA2.AccountOpenDate),
[AccountCloseDate] = MAX(DDA2.AccountCloseDate),
[AccountStatusDesc] = MAX(DDA2.AccountStatusDesc),
[DormantInd] = MAX(DDA2.DormantInd),
[ProductLineName] = MAX(DDA2.ProductLineName),
[ProductCategoryName] = MAX(DDA2.ProductCategoryName),
[ProductTypeName] = MAX(DDA2.ProductTypeName),
[ProductName] = MAX(DDA2.ProductName),
[ProductNumber] = MAX(DDA2.ProductNumber),
[AccountTaxId] = MAX(DDA2.AccountTaxId),
[AccountTaxIdTypeCode] = MAX(DDA2.AccountTaxIdTypeCode),
[AccountTaxStateCode] = MAX(DDA2.AccountTaxStateCode),
[AccountPrimaryBranchName] = MAX(DDA2.AccountPrimaryBranchName),
[MailingAddress1] = MAX(DDA2.MailingAddress1),
[MailingAddress2] = MAX(DDA2.MailingAddress2),
[MailingCityName] = MAX(DDA2.MailingCityName),
[MailingStateCode] = MAX(DDA2.MailingStateCode),
[MailingStateName] = MAX(DDA2.MailingStateName),
[MailingPostalCode] = MAX(DDA2.MailingPostalCode),
[MailingCountryCode] = MAX(DDA2.MailingCountryCode),
[MailingCountryName] = MAX(DDA2.MailingCountryName),
[CurrencyBasedAccountInd] = MAX(DDA2.CurrencyBasedAccountInd),
[MaturityDate] = MAX(DDA2.MaturityDate),
[OriginalLoanAmount] = MAX(DDA2.OriginalLoanAmount),
[CollateralTypeDesc] = MAX(DDA2.CollateralTypeDesc),
[CollateralTypeCode] = MAX(DDA2.CollateralTypeCode),
[InsuredAmount] = MAX(DDA2.InsuredAmount),
[EmployeeInd] = MAX(DDA2.EmployeeInd)
FROM
dbo.DesDimAccount DDA2 (NOLOCK)
GROUP BY
DDA2.AccountNumber,
DDA2.AccountTypeDesc
)
DDA ON RTRIM(TT.[Description]) = RTRIM(DDA.AccountTypeDesc) AND
H.AccountNumber = DDA.AccountNumber
EDIT: I replaced the query with the AS keyword. I get the same error.
MS Access Query with Error:
SELECT
'H' AS [HeaderRecordIndicator],
'1' AS [SupervisingAgency],
'0' + I.InstitutionCode AS [InstitutionCode],
CONVERT(char(8), H.Date, 112) AS [ReportDate],
'CTR' AS [ReportType],
'21' AS [FormatCode],
'1' AS [SubmissionType]
FROM
(((
SELECT
IIF(ISNULL(FE.IsoCode), FORMAT(DFCF.CurrencyAmount, "##################.00"), FORMAT(DFCF.CurrencyAmount * FE.PhpConversionRate, "##################.00")) AS [PesoAmount],
DFCF.TransactionNumber,
DFCF.AccountNumber,
DFCF.CountryCd,
DFCF.TransactionTypeCd,
DFCF.Time,
DFCF.Date,
DFCF.TransactionStatusCd,
DFCF.TransactionCurrencyCd,
DFCF.BranchNumber,
DFCF.RemitterExtPartyCd,
DFCF.BeneficiaryExtPartyCd,
DFCF.PostedDate,
DFCF.AssociateNumber,
DFCF.ExecutingPartyNumber,
DFCF.CurrencyAmount,
DFCF.CurrencyAmountInTxnCcy,
DFCF.CurrencyAmountInAccountCcy,
DFCF.SecondaryAccountKey,
DFCF.RelatedInd,
DFCF.ThirdPartyInd,
DFCF.TransactionDescription,
DFCF.SecurityName,
DFCF.DealNumber
FROM
DesFactCashFlow DFCF LEFT JOIN
ForeignExchange FE ON DFCF.TransactionCurrencyCd = FE.IsoCode
) AS
H LEFT JOIN
Ctr C ON H.PesoAmount = C.PesoAmountFaceValueSumInsured AND
H.AccountNumber = C.AccountNumber AND
H.TransactionTypeCd = C.TransactionType) LEFT JOIN
TransactionType TT ON H.TransactionTypeCd = TT.Code) LEFT JOIN
(
SELECT
DDA2.AccountNumber AS [AccountNumber],
DDA2.AccountTypeDesc AS [AccountTypeDesc],
MAX(DDA2.LineOfBusinessName) AS [LineOfBusinessName],
MAX(DDA2.AccountCurrencyCode) AS [AccountCurrencyCode],
MAX(DDA2.AccountCurrencyName) AS [AccountCurrencyName],
MAX(DDA2.AccountRegistrationTypeDesc) AS [AccountRegistrationTypeDesc],
MAX(DDA2.AccountRegistrationName) AS [AccountRegistrationName],
MAX(DDA2.AccountName) AS [AccountName],
MAX(DDA2.AlternateName) AS [AlternateName],
MAX(DDA2.AccountOpenDate) AS [AccountOpenDate],
MAX(DDA2.AccountCloseDate) AS [AccountCloseDate],
MAX(DDA2.AccountStatusDesc) AS [AccountStatusDesc],
MAX(DDA2.DormantInd) AS [DormantInd],
MAX(DDA2.ProductLineName) AS [ProductLineName],
MAX(DDA2.ProductCategoryName) AS [ProductCategoryName],
MAX(DDA2.ProductTypeName) AS [ProductTypeName],
MAX(DDA2.ProductName) AS [ProductName],
MAX(DDA2.ProductNumber) AS [ProductNumber],
MAX(DDA2.AccountTaxId) AS [AccountTaxId],
MAX(DDA2.AccountTaxIdTypeCode) AS [AccountTaxIdTypeCode],
MAX(DDA2.AccountTaxStateCode) AS [AccountTaxStateCode],
MAX(DDA2.AccountPrimaryBranchName) AS [AccountPrimaryBranchName],
MAX(DDA2.MailingAddress1) AS [MailingAddress1],
MAX(DDA2.MailingAddress2) AS [MailingAddress2],
MAX(DDA2.MailingCityName) AS [MailingCityName],
MAX(DDA2.MailingStateCode) AS [MailingStateCode],
MAX(DDA2.MailingStateName) AS [MailingStateName],
MAX(DDA2.MailingPostalCode) AS [MailingPostalCode],
MAX(DDA2.MailingCountryCode) AS [MailingCountryCode],
MAX(DDA2.MailingCountryName) AS [MailingCountryName],
MAX(DDA2.CurrencyBasedAccountInd) AS [CurrencyBasedAccountInd],
MAX(DDA2.MaturityDate) AS [MaturityDate],
MAX(DDA2.OriginalLoanAmount) AS [OriginalLoanAmount],
MAX(DDA2.CollateralTypeDesc) AS [CollateralTypeDesc],
MAX(DDA2.CollateralTypeCode) AS [CollateralTypeCode],
MAX(DDA2.InsuredAmount) AS [InsuredAmount],
MAX(DDA2.EmployeeInd) AS [EmployeeInd]
FROM
DesDimAccount DDA2
GROUP BY
DDA2.AccountNumber,
DDA2.AccountTypeDesc
) AS
DDA ON RTRIM(TT.[Description]) = RTRIM(DDA.AccountTypeDesc) AND
H.AccountNumber = DDA.AccountNumber
Here is the simplified query with the same error:
SELECT
*
FROM
(((
SELECT
IIF(ISNULL(FE.IsoCode), FORMAT(DFCF.CurrencyAmount, "##################.00"), FORMAT(DFCF.CurrencyAmount * FE.PhpConversionRate, "##################.00")) AS [PesoAmount],
DFCF.TransactionNumber,
DFCF.TransactionCurrencyCd,
FROM
DesFactCashFlow DFCF LEFT JOIN
ForeignExchange FE ON DFCF.TransactionCurrencyCd = FE.IsoCode
) AS
H LEFT JOIN
Ctr C ON H.PesoAmount = C.PesoAmountFaceValueSumInsured AND
H.AccountNumber = C.AccountNumber AND
H.TransactionTypeCd = C.TransactionType) LEFT JOIN
TransactionType TT ON H.TransactionTypeCd = TT.Code) LEFT JOIN
(
SELECT
DDA2.AccountNumber AS [AccountNumber],
DDA2.AccountTypeDesc AS [AccountTypeDesc],
MAX(DDA2.LineOfBusinessName) AS [LineOfBusinessName],
FROM
DesDimAccount DDA2
GROUP BY
DDA2.AccountNumber,
DDA2.AccountTypeDesc
) AS
DDA ON RTRIM(TT.[Description]) = RTRIM(DDA.AccountTypeDesc) AND
H.AccountNumber = DDA.AccountNumber
Give up trying to convert the SQL text from your T-SQL query to Access SQL. Create a new Access query from scratch and use the T-SQL query only as a road map. Add your data sources and set up the joins. The query designer will guarantee you create the joins in the manner which keeps the db engine happy: addition and positioning of parentheses it requires for queries with more than one join; the rules which apply for LEFT JOINs; and so forth. Just let the designer handle those details for you.
The designer will choke in Design View due to the functions in this part of your last join:
RTRIM(TT.[Description]) = RTRIM(DDA.AccountTypeDesc)
So leave out the RTRIM() functions while you're setting up the joins in Design View. Don't worry that the query doesn't return the correct results. After you get joins which satisfy the db engine, switch to SQL View and add the RTRIM() functions back in.
After you get the joins set up correctly, then add in your field expressions to the SELECT list.
Also you may find it easier to manage your complex query by breaking out the subqueries as separate saved queries --- then reference those queries by name in the master query just as you would table sources.
The problem is with the penultimate line:
DDA ON RTRIM(TT.[Description]) = RTRIM(DDA.AccountTypeDesc) AND
The Design View of the Access query designer can't work with functions in the ON part of the clause. You must remove the RTRIM.
Access is parenthesis happy. Wrap each join expression in parentheses, the ON clauses themselves, and each pair of tables.
You can't use CONVERT, NOLOCK, or CASE.
Which version of MSAccess you are using in your system? I just tried in 2007 version and RTRIM is working.

Converting complex sql stored proc into linq

I'm using Linq to Sql and have a stored proc that won't generate a class. The stored proc draws data from multiple tables into a flat file resultset.
The amount of data returned must be as small as possible, the number of round trips to the Sql Server need to be limited, and the amount of server-side processing must be limited as this is for an ASP.NET MVC project.
So, I'm trying to write a Linq to Sql Query however am struggling to both replicate and limit the data returned.
Here's the stored proc that I'm trying to convert:
SELECT AdShops.shop_id as ID, Users.image_url_75x75, AdShops.Advertised,
Shops.shop_name, Shops.title, Shops.num_favorers as hearts, Users.transaction_sold_count as sold,
(select sum(L4.num_favorers) from Listings as L4 where L4.shop_id = L.shop_id) as listings_hearts,
(select sum(L4.views) from Listings as L4 where L4.shop_id = L.shop_id) as listings_views,
L.title AS listing_title, L.price as price, L.listing_id AS listing_id, L.tags, L.materials, L.currency_code,
L.url_170x135 as listing_image_url_170x135, L.url AS listing_url, l.views as listing_views, l.num_favorers as listing_hearts
FROM AdShops INNER JOIN
Shops ON AdShops.shop_id = Shops.shop_id INNER JOIN
Users ON Shops.user_id = Users.user_id INNER JOIN
Listings AS L ON Shops.shop_id = L.shop_id
WHERE (Shops.is_vacation = 0 AND
L.listing_id IN
(
SELECT listing_id
FROM (SELECT l2.user_id , l2.listing_id, RowNumber = ROW_NUMBER() OVER (PARTITION BY l2.user_id ORDER BY NEWID())
FROM Listings l2
INNER JOIN (
SELECT user_id
FROM Listings
GROUP BY
user_id
HAVING COUNT(*) >= 3
) cnt ON cnt.user_id = l2.user_id
) l2
WHERE l2.RowNumber <= 3 and L2.user_id = L.user_id
)
)
ORDER BY Shops.shop_name
Now, so far I can return a flat file but am not able to limit the number of listings. Here's where I'm stuck:
Dim query As IEnumerable = From x In db.AdShops
Join y In (From y1 In db.Shops
Where y1.Shop_name Like _Search + "*" AndAlso y1.Is_vacation = False
Order By y1.Shop_name
Select y1) On y.Shop_id Equals x.shop_id
Join z In db.Users On x.user_id Equals z.User_id
Join l In db.Listings On l.Shop_id Equals y.Shop_id
Select New With {
.shop_id = y.Shop_id,
.user_id = z.user_id,
.listing_id = l.Listing_id
} Take 24 ' Fields ommitted for briefity...
I assume to select a random set of 3 listings per shop, I'd need to use a lambda expression however am not sure how to do this. Also, need to add in somewhere consolidated totals for listing fieelds against individual shops...
Anyone have any thoughts?
UPDATE:
Here's the current solution that I'm looking at:
Result class wrapper:
Public Class NewShops
Public Property Shop_id As Integer
Public Property listing_id As Integer
Public Property tl_listing_hearts As Integer?
Public Property tl_listing_views As Integer?
Public Property listing_creation As Date
End Class
Linq + code:
Using db As New Ads.DB(Ads.DB.Conn)
Dim query As IEnumerable(Of IGrouping(Of Integer, NewShops)) =
(From x In db.AdShops
Join y In (From y1 In db.Shops
Where (y1.Shop_name Like _Search + "*" AndAlso y1.Is_vacation = False)
Select y1
Skip ((_Paging.CurrentPage - 1) * _Paging.ItemsPerPage)
Take (_Paging.ItemsPerPage))
On y.Shop_id Equals x.shop_id
Join z In db.Users On x.user_id Equals z.User_id
Join l In db.Listings On l.Shop_id Equals y.Shop_id
Join lt In (From l2 In db.Listings _
Group By id = l2.Shop_id Into Hearts = Sum(l2.Num_favorers), Views = Sum(l2.Views), Count() _
Select New NewShops With {.tl_listing_views = Views,
.tl_listing_hearts = Hearts,
.Shop_id = id})
On lt.Shop_id Equals y.Shop_id
Select New NewShops With {.Shop_id = y.Shop_id,
.tl_listing_views = lt.tl_listing_views,
.tl_listing_hearts = lt.tl_listing_hearts,
.listing_creation = l.Creation,
.listing_id = l.Listing_id
}).GroupBy(Function(s) s.Shop_id).OrderByDescending(Function(s) s(0).tl_listing_views)
Dim Shops as New Dictionary(Of String, List(Of NewShops))
For Each item As IEnumerable(Of NewShops) In query
Shops.Add(item(0).shop_name, (From i As NewShops In item
Order By i.listing_creation Descending
Select i Take 3).ToList)
Next
End Using
Anyone have any other suggestions?
From the looks of that SQL and code, I'd not be turning it into LINQ queries. It'll just obfuscate the logic and probably take you days to get it correct.
If SQLMetal doesn't generate it properly, have you considered using the ExecuteQuery method of the DataContext to return a list of the items you're after?
Assuming that your sproc you're trying to convert is called sp_complicated, and takes in one parameter, something like the following should do the trick
Protected Class TheResults
Public Property ID as Integer
Public Property image_url_75x75 as String
'... and so on and so forth for all the returned columns. Be careful with nulls
End Class
'then, when you want to use it
Using db As New Ads.DB(Ads.DB.Conn)
dim results = db.ExecuteQuery(Of TheResults)("exec sp_complicated {0}", _Search)
End Using
Before you freak out, that's not susceptible to SQL Injection. L2SQL uses proper SQLParameters, as long as you use the squigglies and don't just concatenate the strings yourself.

Resources