Query with switch function requests parameter value [duplicate] - excel

This question already has answers here:
Why does this query require a parameter?
(2 answers)
Closed 3 years ago.
Background: Excel worksheet as front end to an Access database. Excel contains VBA code and uses ADODB to move values into and out of the tables in Access.
One column is a composite value which describes a complex priority relationship. One digit for priority level (1-6), one letter for more granular level (A-C), and a type of project (Safety, Security, Enviro, etc.) The values look like "2B - Maint.", "2A - ProcCntl"
I need to sort the results of a select * query in different ways. Sometimes with the typical Alpha sort which would list 1A values before 1B before 4C. Other times I need to sort all the Safety as a group, Maint. as another, etc. A simple alpha sort on the project type doesn't work because the manager wants a specific order.
I am using the Switch function to assign the order. I have found a couple of ways to make this work in Access but they all ask for a parameter value when I run the query. Entering a blank value gets the desired result. Moving the query into the VBA of Excel returns an error complaining of an empty parameter.
Here is one of the "working" queries:
SELECT *, Mid([Priority],6,2) AS ProjClass,
Switch(ProjClass="Sa",1,ProjClass="En",2,ProjClass="Se",3,ProjClass="6S",4,ProjClass="Qu",5,ProjClass="Pr",6,ProjClass="Ma",7,ProjClass="Bu",8)
AS [FirstSort]
FROM tblProjects
ORDER BY [FirstSort] ASC, [Priority] ASC;
When I run this through the VBA I get
Run-time error "No value given for one or more required parameters."
When I run it in Access a "Enter Parameter Value" dialog opens asking for FirstSort. I click through and see the result is correctly sorted.
The root question: Why is Access seeing FirstSort as a parameter and not a field name?
I think I need to understand that before I can fix the VBA issue.

More research has revealed yet another Access quirk: The problem is that MS Access does not allow AS clauses in the ORDER BY clause.
So a little experimentation lead me to change the ORDER BY clause to ORDER BY 3 ASC, [Priority] ASC;
I chose the three because it is the third field expression in the query. It works but it would be great if someone could clarify the specific rule that makes it work.
Hat tip: Why does this query require a parameter? and onedaywhen's answer.

ProjClass is a field created during execution of the query. Before that when the SQL engine is determining an execution plan for the query it will not recognize that field name so assumes it is parameter. SORT is done at the end of the query and by that time the engine knows which is the third field.
An alternative is to create another table called something like tblPriority with 2 columns ProjectClass and SortOrder
ProjClass SortOrder
Sa 1
En 2
Se 3
6S 4
Qu 5
Pr 6
Ma 7
Bu 8
and use a JOIN
SELECT A.* FROM tblProjects AS A
LEFT JOIN tblPriority as B
ON B.ProjClass = Mid(A.Priority,6,2)
ORDER BY SortOrder

Related

Multi select employees in Employee Time Activities

I was trying to enable multi-select for Owner in Employee Time Activities and wanted to try based on below article.
https://asiablog.acumatica.com/2018/01/multi-select-selector.html
Then override view like below:
https://asiablog.acumatica.com/2017/11/sql-in-operator-in-bql.html
However, after I added ValidateValue = false in field:
I am getting this error.
I looked at the custom attribute and I don't think it could be replaced with anything keeping the same implementation.
So, is there any other way I can accomplish multi select feature to allow display Employee Time Activities for selected employees at once besides the ideas mentioned above?
Thanks.
Your primary issue is that DimensionSelector is different than Selector.
Secondary thing to keep in mind that when you do Multiselector you would need to update the field that holds the values to have a longer length. The way a multiselector works is that it stored the saved values as a ; (semicolon) separated string. so if the field was 10 long you would want to expand to whatever you expect the max number of selected values would be, e.g. 40 would be 480, 40x10 + 40x2, 10 being the original size, 2 being a semicolon and space. (hope that makes sense :) )
Next you would have to update all the functional business logic to then parse that string and loop each, in this case, employee for the functions.
I am speaking very generically here. So not sure what you're actually attempting to do here, but one would assume that if you were selecting multiple employees you would want records to reflect accordingly.

Multi LookUp - Check for unique values

I´m trying to set up unique values in my PowerApp-Form. The data is stored in a Sharepoint list. I have a column called watches, items in this column have a unique number, which have to be unique. People can pick multiple of those watches in a LookUp-field. But before submitting the form, I need to check if those picked values already exist in my list and at least display an error message.
I have setup a regular text field and added following rule to it:
If(LookUp(MyList.Watches;DataCardValue4.SelectedItems.Value in Watches;"OK")<>"OK";"No Error";"Watch already exist")
DataCardValue4 is my LookUp field, where people can pick those watches. With this rule I want to check if a item already is in my column watches and let my text field display the error. Somehow the rule doesn´t work.
Can you tell me how I compare multiple lookup choices to my table/column entries?
The first parameter to the LookUp function should be the table (SharePoint list) rather than the column. So the first parameter should be 'MyList' rather than 'MyList.Watches'. Also, I'm not sure that the formula provided (second parameter to LookUp) will work. In your formula, you will be looking for multiple items (DataCardValue4.SelectedItems.Value) within multiple items (Watches). Perhaps you can update your app to have users only pick one watch value before submitting?
One last thing to note. I'm not sure how big you expect your SharePoint list to get, but I would highly recommend keeping your LookUp formula within the bounds to support delegation. More specifically, SharePoint has different formula requirements than other connectors. For example, you can use '=' in your formula, but not 'in'.
Your new rule might look something like below. Please note that it could have syntax errors and might not even be delegable in it's current form since I am providing the rule with no checking. Also, I switched from using LookUp to using Filter instead just because I'm more familiar with Filter. However, both functions are very similar.
If(CountRows(Filter(MyList; DataCardValue4.Selected.Value = Watches)) > 0; "Watch already exist"; "No Error")

Prompt Page Static Choices

I am trying to create a prompt on my prompt page to let the user select a specific quarter. for example, the user would select "2018 Q1" from a prompt and the report would know that the dates for "2018 Q1" are between 7/1/2018 and 9/30/2018. Is this possible to do? I have been messing with the static choices, but I am not getting very far.
My Cognos knowledge would be classified as general.
There are a couple ways to do that. You didn't indicate whether you want the choices offered the user in the prompt to be dynamic. Dynamic prompts usually provide a better customer experience and require less maintenance. I'll explain how to do dynamic and if you want static, simply hand enter the values into the prompt rather than source them from a query. The rest of the instructions apply.
Dynamic (preferred)
Create a new query
Name the query something that indicates its function, e.g. 'Quarter Prompt'
Within the query create a new data item to contain what you want the prompt to display to the user.
For example, if you wanted the prompt to show "2018 Q1" you might create this string from a Date table like so:
[Year] + ' Q' + [Quarter]
If you generate the tabular data for this query you will get a list of all year/quarter combinations in your date table:
2018 Q1
2018 Q2
2018 Q3
2018 Q4
2017 Q1
...
Constrain the list to only the range of quarters you want to prompt for.
For instance, if you wanted to only show quarters in the current year you'd add this filter:
[Year] = year(current_date)
After adding this filter you will only see the first four rows of the above output returned. Your users will be given four choices to choose from.
Set the value prompt's Query property to the new query and set both the Use Value and Display Value properties to the data item you defined in the prompt query
To apply the prompt choice to your report, you simply add a filter to the relevant report query that takes the input from the user and compares it against the data:
[Year] + ' Q' + [Quarter] = ?quarterPrompt?
Now, this way of doing it has some potential performance inefficiencies. In order to apply the filter each row will have to be examined, converted into the string format and compared. If you need better performance a better way to do the filter is as follows:
[Year] = substring(?quarterPrompt?,1,4) AND [Quarter] = substring(?quarterPrompt?,7,1)
Since we are only transforming the prompt, which contains only one value and not many, the performance is optimized.
Addendum
My intuition was telling me that there might be an even better way. After poking around, I realized that there's an even more efficient way to handle this by eliminating all string parsing. Here's the parts of the procedure to be amended:
You need to add a new data item as the Use Value passed into the report query.
Create a second data item in the prompt query with the following expression:
[Year] * 100 + [Quarter]
For every year and quarter combination you will now have a number that encodes the combination. For instance, for year 2018 and quarter 2 the new data item will return 201802.
Change the prompt properties. Point the Use Value to the newly created data item.
Change the filter in the report query to use the new numerical value
This would look something like the following:
floor(?quarterPrompt?/100) = [Year]
AND mod(?quarterPrompt?,100) = [Quarter]
This numerical-only operation has the potential to have better performance than the substring-based parsing in the original answer, yet has the same effect.

Reading an Excel sheet using ADO/ODBC in Delphi 7

I'm trying to read an Excel sheet from an XLS or XLSX file in memory using Delphi 7. When possible I use automation to read the cells one by one, but when Excel is not installed, I revert to using the ADO/ODBC Jet driver.
I connect using either
Provider=Microsoft.Jet.OLEDB.4.0; Data Source=file.xls;Extended Properties="Excel 8.0;Persist Security Info=False;IMEX=1;HDR=No";
Provider=Microsoft.ACE.OLEDB.12.0; Data Source=file.xlsx;Extended Properties="Excel 12.0;Persist Security Info=False;IMEX=1;HDR=No";
My problem then is that when I use the following query:
SELECT * FROM [SheetName$]
the returned results do not contain the empty rows or empty columns, so if the sheet contains such rows or columns, the following cells are shifted and do not end up in their correct position. I need the sheet to be loaded "as is", ie know exactly from what cell position each value comes from.
I tried to read the cells one by one by issuing one query of the form
SELECT F1 FROM `SheetName$A1:A1`
but now the driver returns an error saying "There is data outside the selected region". btw I had to use backticks to enclose the name because using brackets like this [SheetName$A1:A1] gave out a syntax error message.
Is there a way to tell the driver to select the sheet as-is, whithout skipping blanks? Or maybe a way to know from which cell position each value is returned?
For internal policy reasons (I know they are bad but I do not decide these), it is not possible to use a third party library, I really need this to work from standard Delphi 7 components.
I assume that if your data is say in the range B2:D10 for example, you want to include the column A as an empty column? Maybe? Is that correct? If that's the case, then your data set, when you read the sheet (SELECT * FROM [SheetName$]) would also return 1 million rows by 16K columns!
Can you not execute a query like: SELECT * FROM [SheetName$B2:D10] and use the ADO GetRows function to get an array - which will give you the size of the data. Then you can index into the array to get what data you want?
OK, the correct answer is
Use a third party library no matter what your boss says. Do not even
try ODBC/ADO to load arbitrary Excel files, you will hit a wall sooner or later.
It may work for excel files that contain a single data table, but not when you want to cherry pick data in a sheet primarily made for human consumption (ie where a single column contains some cells with introductory text, some with numerical data, some with comments, etc...)
Using IMEX=1 ignores empty lines and empty columns
Using IMEX=0 sometimes no longer ignores empty lines, but now some of the first non empty cells are considered field names instead of data, although HDR=No. Would not work anyway since valules in a column are of mixed types.
Explicitly looping across cells and making a SELECT * FROM [SheetName$A1:A1] works until you reach an empty cell, then you get access violations (see below)
Access violation at address 1B30B3E3 in module 'msexcl40.dll'. Read of address 00000000
I'm too old to want to try and guess the appropriate value to use so it works until someone comes with yet another mix of data in a column. Sorry for having wasted everybody's time.

Crystal Reports - my formula works, but when repeated in more than 1 subreport, all records disappear

I'm not a developer but I'm supposed to create a report by C.R., so excuse me in advance if it is an obvious question for you, and please keep in mind that I'm a real beginner.
I have a job composed of 3 different workings (3 out of 5, which is the maximum workings I can have for a job).
In my SQL database, the table.field corresponding to those workings is job.phase, so when I put, in my report details, the field "job.phase", I get 3 rows for that job.
The point is that my report printout always has to show 5 different text objects (one below the other), corresponding to the descriptions of all the 5 possible table.field-records, and a 'X' should appear next to text objects when each one of the workings listed there is a part of my job (otherwise nothing should appear).
What I have done is the following:
- created a subreport containing the "job.phase" field
- put it near my first text object
- specified in my subreport the following "show string" formula:
if job.phase = 'working1' then 'X' else ''
and it works: a X appears if working1 is part of my job, nothing appears if working1 is not part of my job.
Then I have created 4 subreports more, equal to the first one, and specified the same for job.phase = working2, working3, working4 and working5, BUT, after doing that, no X is shown (even though working 1, 2 and 3 are part of my job)...
Is there anybody who can help me, please? It's so frustrating...
Using subreports for something like this is overkill for what you're trying to do and could be causing any number of things to behave badly. I'd recommend you abandon that idea. Here's how I would do it:
The first thing you'll want to do is group by job (if more than one will appear in your report, which I'll assume it will). The Group Footer section is where you can display the labels and Xs. You'll need to create 5 formulas as you did before if {job.phase} = "working1" then "X", one for each of the phases/workings. Drop all 5 of those formulas into the Details section of the report and then suppress that entire section so that it doesn't display.
To show the Xs, you can use a Maximum summary in the Group Footer for each of the five formulas you created. To do this, right-click each of the formulas in turn, select Insert -> Summary. Choose Maximum as the summary, and "Group 1" (Your job ID or whatever field you are using to group the job) as the Location. That will insert a field into the Group Footer that will display an X when that particular working is specified for the job, otherwise it won't display anything. Move them to display next to the appropriate label/text field and you're done.

Resources