Alternatives to macros for accessing data objects - vbscript

I'm about to begin implementing a new version of an Email marketing program for my company. The old version of the program program heavily depended on micros and has about 2000 lines to prepare data for an email campaign to be run. But I have read somewhere that macros are not the best solution to run such heavy tasks and it's better we keep them for simple things.
I'm quite new to QV and I'm the kind of person that likes to learn as I go and not complete a big reference book before I start a project. I'm good at C# and Java but I realized QlikView scripts are in either VBScript or JScript. I have no experience with them whatsoever but they don't look very complicated to me at first glance.
What I was wondering was whether there is a better way of handling data in QlikView? That means can I use another programming language or do you suggest I stick to the script languages provided by QV? Because one big problem I've seen is that as macros get larger they become very hard to debug.
In the old version of our program developed by one of my colleagues who has now left the company, as soon as there was an error in preparing the data, all we got was the macros window with no clue about where the error had taken place. As I would like to implement this project incrementally and little by little, I would like to have a good mechanism for trouble shooting rather than goring though a 2000-line script to understand where the problem comes from.
Your suggestions about how to bring this project to a safe shore are very welcome. So, any good plugins or 3rd party app to monitor the data and facilitate my implementation can help.

We are an outlier there. We are using the OCX and connect to it in winforms.
We have then standard c# code with everything debuggable and it makes everyone here very happy indead after using endless amount of time debugging javascripts.
The users use QV for selecting stuff and then we use the selected event in the OCX and pull the selected data from QV for postprocessing and tag the QV data with dynamic sql update.
I do not nessesarily recommend this method, but it has increased dramatically the development output for us when using QV for datamining and then processing the data selected.
Next project we are not going to use the OCX. But all the buisness logic and postprocessing is in a com visible c# dll' that we access through vbscript macro.
EDIT. More details
This is the current setup communicating with the document through OCX
Change a selection
axQlikMainApp.ActiveDocument.Fields("%UnitID").Clear();
var selSuccess = axQlikMainApp.ActiveDocument.Fields(cls.QlikView.QvEvalStr.Fields.UnitId).Select("(%UnitID)");
reset a sheet object
axQlikMainApp.ActiveDocument.ClearCache();
axQlikMainApp.ActiveDocument.GetSheetObject("Document\\MySheetObjectName").Restore();
get a string from QV
string res axQlikMainApp.ActiveDocument.Evaluate("=concat(Distinct myField1 &'|' & MyField2,'*')");
and can get horribly complicated
string res axQlikMainApp.ActiveDocument.Evaluate( "=MaxString({1 <%UnitID= {" + sUnitIds + #"}>}'<b>' & UnitName & '</b> \r\n bla bla bla:' & UnitNotesPlanning) & " +
"'\n title1: ' & Count({1 <%UnitID= {" + sUnitIds +#"},%ISODate={'" + qlickViewIsoDate + "'},Need = {'Ja'}" + MinusCalc + ">}Distinct %CivicRegNo) & " +
"'\n Title2: ' & Count({1 <%UnitID= {" + sUnitIds + #"},%ISODate={'" + qlickViewIsoDate + "'} " + recallMinusCalc + ">}DISTINCT RevGUID) & " +
"'\n Title3: ' & Count({1 <%UnitID= {" + sUnitIds + #"},%ISODate={'" + qlickViewIsoDate + "'},Need2 = {'Ja'}>}Distinct %CivicRegNo) & '" +
"\n Title4:' & MinString({1 <%UnitID= {" + sUnitIds + #"},FutureBooking = {1}>} Date(BookingStart) & ' Beh: ' & If(IsNull(ResourceDisplayedName),'_',ResourceDisplayedName)) &'" +
"\n Title5:' & MaxString({1 <%UnitID= {" + sUnitIds + #"},FutureBooking = {0}>} Date(BookingStart) & ' Beh: ' & If(IsNull(ResourceDisplayedName),'_',ResourceDisplayedName)) &''" +
" & MaxString({1 <%UnitID= {" + sUnitIds + #"}>}if(UnitGeo_isRelocatedOnSameGeo=1,'\nOBS! Multiple geo addresses. Zoom!',''))" +
""
);

Related

MS Visual Studio (Reporting Services)

I've worked in SSRS for years but have never learned what this type of coding is actually named (which makes searching for solutions difficult), can anyone help please? Below is an example which allows the developer to have the code run as one continuous string. It also, if you're not familiar, allows for many powerful functions to be used that would otherwise (to my knowledge) not be available (e.g., IIF's, INSTR(JOIN()), SWITCH's, etc.).
=
" select distinct bn " &
" into #ST " &
" from frm_cr_2021 a " &
" join Md..nui_crssw b " &
" ON a.rc=b.cy"&MID(YEAR(Parameters!frm_dt.Value),3,2)&"_rc" &
" join nd_bs..dg_cv c " &
" on b.nd=c.nd " &
" where a.f_Dt<=#frm_dt and a.tr_dt>=#frmy_dt " &
"(select distinct c.ln,a.RC,A.Tr_Lv,a.P_Typ,a.P_Gp,a.Eff_Date,a.Term_Date from frm_"&YEAR(Parameters!frm_dt.Value)&" a "

Getting Microsoft VBScript runtime error '800a0009' on Checkout Cart

I'm really not very familiar with ASP, but the site I'm managing is spitting that error out to me. Here is the full code from the site:
Microsoft VBScript runtime error '800a0009'
Subscript out of range: '[number: 1]'
/shopping_sub.asp, line 715.
Here is the code from 697-728:
'Response.write strPass & "<p>"
'Response.write "Response: " & strResp
'Response.end
If strResp="ERROR" then
RESULT_num_shipping_options = -1
Session("ShipErrMsg")="To continue your order, please contact customer service regarding your contact information. Thank you."
Else
RESULT_num_shipping_options=1
vResp=Split(strResp,":")
Dim RESULT_shipping_description_array(4)
Dim RESULT_shipping_amount_array(4)
For I = 0 to UBound(vResp)
vResp2=Split(vResp(I),"|")
RESULT_shipping_description_array(I)=vResp2(0)
RESULT_shipping_amount_array(I)=vResp2(1)
Next
End If
Else
RESULT_num_shipping_options = -1
cShipping=0
End If
End If
'Response.write "Weight: " & siWeight & "<br/>"
'Response.write "Zip: " & receiverpostalcode & "<br/>"
'Response.write "Country: " & receivercountrycode & "<br/>"
It appears to start functioning after 7 items have been added to the cart, but anything less than that returns errors.
This doesn't happen with all products, so any idea?
Have you used a debugger to determine the value of vResp and the array length of vResp2?
My guess is that the response is not what you expected. If you can't force the api to always have the correct response, then you'll want to protect against it by checking the length of the split response before trying to access the value.
Another problem I see that is unrelated, is that if the UBound(vResp)_ > 4, then you'll get a similar error

Understanding the output log's auto layout data

I'm debugging a crash that I believe is auto layout related. When the crash occurs, I get an enormous dump of information on the output area that begins like this:
2015-06-04 13:23:44.158 SpeedySend[22084:861374] Objective: {objective
0x7f99e06b3730: <500:242.5, 250:18443.5> +
<500:1>*0x7f99e061e570.negError{id: 4899} +
<500:1>*0x7f99e061e570.posErrorMarker{id: 4898} + <500:1,
250:-1>*0x7f99e061f940.negError{id: 4913} + <500:1,
250:1>*0x7f99e061f940.posErrorMarker{id: 4912} + <500:1,
250:-1>*0x7f99e061fb40.negError{id: 4915} + <500:1,
250:1>*0x7f99e061fb40.posErrorMarker{id: 4914} + <500:1,
250:-2>*0x7f99e0620890.negError{id: 4807} + <500:1,
250:2>*0x7f99e0620890.posErrorMarker{id: 4806} +
<500:2>*0x7f99e06496f0.posErrorMarker{id: 4916} +
<500:2>*0x7f99e0649f40.posErrorMarker{id: 4920} + <50 ...
and then runs on for a very long time and ends like this:
... 250:-1>*0x7f99e1d77ec0.negError{id: 5023} + <800:1,
250:1>*0x7f99e1d77ec0.posErrorMarker{id: 5022} + <500:1,
250:-1>*0x7f99e1d78150.negError{id: 5025} + <500:1,
250:1>*0x7f99e1d78150.posErrorMarker{id: 5024} +
<500:1>*0x7f99e1d78310.negError{id: 5027} +
<500:1>*0x7f99e1d78310.posErrorMarker{id: 5026} +
<500:1>*0x7f99e1d78620.negError{id: 5045} +
<500:1>*0x7f99e1d78620.posErrorMarker{id: 5044} +
<500:1>*0x7f99e1d788c0.negError{id: 5031} +
<500:1>*0x7f99e1d788c0.posErrorMarker{id: 5030} +
<500:1>*0x7f99e1d78d30.negError{id: 5033} +
<500:1>*0x7f99e1d78d30.posErrorMarker{id: 5032} +
<500:1>*0x7f99e1d790a0.negError{id: 5035} +
<500:1>*0x7f99e1d790a0.posErrorMarker{id: 5034} +
<500:1>*0x7f99e1d79460.negError{id: 5037} +
<500:1>*0x7f99e1d79460.posErrorMarker{id: 5036} +
<500:1>*0x7f99e1d79840.negError{id: 5039} +
<500:1>*0x7f99e1d79840.posErrorMarker{id: 5038} +
<500:1>*0x7f99e1d79c50.negError{id: 5041} +
<500:1>*0x7f99e1d79c50.posErrorMarker{id: 5040} +
<500:1>*0x7f99e1d7a080.negError{id: 5043} +
<500:1>*0x7f99e1d7a080.posErrorMarker{id: 5042} +
<500:1>*0x7f99e1d7aa60.negError{id: 5047} +
<500:1>*0x7f99e1d7aa60.posErrorMarker{id: 5046} +
<500:-7.45058e-08>*0x7f99e1f7ae60.negError{id: 3600}}
I would like to understand this data better as an aid to debugging my problem.
Is there a document or a posting that I can access that explains the format and meaning of this data?
Like, for instance, what does something like <500:1,250:-1> represent?
What is a negError?
And, most importantly, can something like {id: 3600} be tied back to a specific control that auto layout is laying out for me?
I'm particularly interested in the last questions because I've read here that very small numbers, when seen in these dumps, can indicate a crash due to accumulated loss of floating point precision in the auto layout engine.
You'll note that I have such a number on the very last line of my output data. So, if I can relate {id: 3600} back to one of my controls, I hope that will put me close to the origin of the problem.

Is it possible to import existing SSRS reports in Visual Studio?

When upgrading a machine, we lost the Visual Studio project that was used to create SSRS reports. The Data Sources and the Reports still exist on the server however. Is there a way to re-create the VS project using what it on the SQL server? Is there a way to create a new Reporting Services project and to import existing Data Sources and Reports in it?
I believe the reports were originally created using VS 2005.
You haven't lost much.
The data sources are not much: the connection string to a database, and possibly settings for caching and authentication. These should be easily recreated.
The report definitions (.rdl files) can be downloaded for each report type, and added to a new Reporting Services project. They will need to be pointed at the newly recreated datasources, but then should be fine.
To download the report files, go to the Reporting Services Report Manager (website.) For a default instance of SQL with default install options this is http://servername/reports/ If you have admin permissions, there you can browse through the reports. Go to the properties of a given report and click the Edit... button. This will download the .rdl through your browser. (In SSRS 2008, the Edit button was changed to "Download...")
You will need to find out what version of SSRS you are running: the different versions of Business Intelligence Developer Studio (BIDS, the SSAS and SSRS version of Visual Studio) create reports for specific versions of SSRS. The reports can be upgraded, but not downgraded or deployed to an older version of SSRS.
There's now a PowerShell module that will do a nice job of this.
out-rsfoldercontent -reportserveruri http://[reportserver name]/reportserver -RsFolder /[path you'd like to export] -Destination c:\test -recurse
Adjust the parameters to suit.
https://github.com/Microsoft/ReportingServicesTools
SSRS doesn't allow you to download all reports from a report folder in 1 go...
However I found and tweaked a simple piece of SQL I found on the net which we use to great effect on our system...
This is it:-
/*
People working on SSRS are well aware that “Report Manager” does not support downloading all the report files (.rdl files) at one go out-of-box.
However take this script, alter the xxx parameters to your bits. Its works great.
If you get a HOST Error - you need to set full permission to the SQL Server Group on your DOS Dir.
on [Our_Prod_Server], this is: SQLServerMSSQLUser$NS226758$MSSQLSERVER
NOTE: You will find a RETURN; statement below, comment it out once you have altered the parameters.
*/
--Replace NULL with keywords of the ReportManager's Report Path,
--if reports from any specific path are to be downloaded
--select * from [ReportServer].[dbo].[Catalog] CL -- this gives you an idea of the Report Directories.
DECLARE #FilterReportPath AS VARCHAR(500) = 'xxx'
--Replace NULL with the keyword matching the Report File Name,
--if any specific reports are to be downloaded
DECLARE #FilterReportName AS VARCHAR(500) = ''
--Replace this path with the Server Location where you want the
--reports to be downloaded..
DECLARE #OutputPath AS VARCHAR(500) = 'C:\Users\[uuuuu]\Documents\Visual Studio 2012\Projects\Report Skeleton\[Report DIR Name]\'
--Used to prepare the dynamic query
DECLARE #TSQL AS NVARCHAR(MAX)
RETURN;
--Reset the OutputPath separator.
SET #OutputPath = REPLACE(#OutputPath,'\','/')
--Simple validation of OutputPath; this can be changed as per ones need.
IF LTRIM(RTRIM(ISNULL(#OutputPath,''))) = ''
BEGIN
SELECT 'Invalid Output Path'
END
ELSE
BEGIN
--Prepare the query for download.
/*
Please note the following points -
1. The BCP command could be modified as per ones need. E.g. Providing UserName/Password, etc.
2. Please update the SSRS Report Database name. Currently, it is set to default - [ReportServer]
3. The BCP does not create missing Directories. So, additional logic could be implemented to handle that.
4. SSRS stores the XML items (Report RDL and Data Source definitions) using the UTF-8 encoding.
It just so happens that UTF-8 Unicode strings do not NEED to have a BOM and in fact ideally would not have one.
However, you will see some report items in your SSRS that begin with a specific sequence of bytes (0xEFBBBF).
That sequence is the UTF-8 Byte Order Mark. It’s character representation is the following three characters, “”.
While it is supported, it can cause problems with the conversion to XML, so it is removed.
*/
SET #TSQL = STUFF((SELECT
';EXEC master..xp_cmdshell ''bcp " ' +
' SELECT ' +
' CONVERT(VARCHAR(MAX), ' +
' CASE ' +
' WHEN LEFT(C.Content,3) = 0xEFBBBF THEN STUFF(C.Content,1,3,'''''''') '+
' ELSE C.Content '+
' END) ' +
' FROM ' +
' [ReportServer].[dbo].[Catalog] CL ' +
' CROSS APPLY (SELECT CONVERT(VARBINARY(MAX),CL.Content) Content) C ' +
' WHERE ' +
' CL.ItemID = ''''' + CONVERT(VARCHAR(MAX), CL.ItemID) + ''''' " queryout "' + #OutputPath + '' + CL.Name + '.rdl" ' + '-T -c -x'''
FROM
[ReportServer].[dbo].[Catalog] CL
WHERE
CL.[Type] = 2 --Report
AND '/' + CL.[Path] + '/' LIKE COALESCE('%/%' + #FilterReportPath + '%/%', '/' + CL.[Path] + '/')
AND CL.Name LIKE COALESCE('%' + #FilterReportName + '%', CL.Name)
FOR XML PATH('')), 1,1,'')
--SELECT #TSQL
--Execute the Dynamic Query
EXEC SP_EXECUTESQL #TSQL
END
I used this piece of code, but I had problems with the polish characters in SSRS 2008 R2.
So I added some replaces with replace this "broken" convert:
SET #TSQL = STUFF((SELECT
';EXEC master..xp_cmdshell ''bcp " ' +
' SELECT ' +
' REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE' +
' (REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(CONVERT(VARCHAR(MAX), ' +
' CASE ' +
' WHEN LEFT(C.Content,3) = 0xEFBBBF THEN STUFF(C.Content,1,3,'''''''') '+
' ELSE C.Content '+
' END), ''''Å'''', ''''l''''), ''''Ä™'''', ''''e''''), ''''l›'''', ''''s'''') '+
' , ''''ć'''', ''''c''''), ''''l¼'''', ''''z''''), ''''lš'''', ''''s'''') ' +
' , ''''ó'''', ''''o''''), ''''Ä…'''', ''''a''''), ''''l»'''', ''''Z'''') '+
' , ''''sÄ'''', ''''S''''), ''''†'''', ''''C''''), ''''l‚'''', ''''l'''') ' +
' , ''''Ó'''', ''''O''''), ''''Ę'''', ''''E''''), ''''lº'''', ''''z'''') ' +
' , ''''Ä„'''', ''''A''''), ''''l¹'''', ''''Z'''') '+
' FROM ' +
' [ReportServer].[dbo].[Catalog] CL ' +
' CROSS APPLY (SELECT CONVERT(VARBINARY(MAX),CL.Content) Content) C ' +
' WHERE ' +
' CL.ItemID = ''''' + CONVERT(VARCHAR(MAX), CL.ItemID) + ''''' " queryout "' + #OutputPath + '' + CL.Name + '.rdl" ' + '-T -c -x'''
FROM
[ReportServer].[dbo].[Catalog] CL
WHERE
CL.[Type] = 2 --Report
AND '/' + CL.[Path] + '/' LIKE COALESCE('%/%' + #FilterReportPath + '%/%', '/' + CL.[Path] + '/')
AND CL.Name LIKE COALESCE('%' + #FilterReportName + '%', CL.Name)
FOR XML PATH('')), 1,1,'')

iteration through outlook appointments

I know how to iterate through non-recurring appointments in Outlook.
My question is, how to I iterate through Outlook appointments including the recurring appointments?
Thank you.
If you are open to using 3rd party libraries, I'd suggest using "Redemption" library (http://www.dimastr.com/redemption/). This library has useful RDOFolder2 interface with GetActivitiesForTimeRange method.
Here you can find more information about usage of this interface:
(http://www.dimastr.com/redemption/rdo/rdofolder.htm)
If you don't want to use 3rd party library and need to stick to Outlook API, the trick is to set IncludeRecurrences flag to true before iterating appointments. The following article should provide enough information on how to do that:
(http://www.outlookcode.com/article.aspx?id=30)
Actually there is no need to use third party tools. There is the option IncludeRecurrences which takes care of this:
Set myNameSpace = myOlApp.GetNamespace("MAPI")
Set MyFolder = myNameSpace.GetDefaultFolder(olFolderCalendar)
Set oItems = MyFolder.Items
' Restrict Date
strFilter = "[Start] >= " + "'" + ourStart + "'"
Set oItems = oItems.Restrict(strFilter)
strFilter = "[End] <= " + "'" + ourEnd + "'"
Set oItems = oItems.Restrict(strFilter)
' Restrict Category
strFilter = "[Categories] = " + "'" + ourCategory + "'"
Set oItems = oItems.Restrict(strFilter)
oItems.Sort "[Start]"
' We want recurring, too (http://www.pcreview.co.uk/forums/get-recurring-appointment-dates-vba-t799214.html)
oItems.IncludeRecurrences = True

Resources