I'm currently going through all of our Crystal Reports and changing them to read from Stored Procedures instead of having the joins/tables inside of the report itself.
The problem is, I have to manually remove then add the fields. Is there a way to programmatically or mass change the report fields to avoid wasted man hours? Assuming each field on the report exists by a (slightly) different name in the stored procedure.
Unfortunately there isn't an easy way to do this. You can try going to the database, set datasource location and replacing each table with the stored procedure. Each time you do this you should be prompted to map each field that doesn't have a corresponding entry with the same field name.
Though I think crystal will try to alias the sproc multiple times instead of point all to the same sproc.
I meant to elaborate... When you come to designing more complex reports it's a kind of "best practice" to create formula fields for EVERY field you use in your report. This makes life a lot easier when coming to do something like this in future
Related
I have crystal report that was working before database upgrade. It is only one report that doesnt work. So I would not think of a driver issue.
I am able to test this report using CRs client tools, design and then preview. The preview does not bring any data. A single parameter is used and I am sure there is data because the data is retrieved if I create a new crystal report and also verified the SQL. (So there is no question about the no data or any missing links -- its a simple view).
This cannot be a driver issue as well, as all other old reports still work.
Have also tried deleting all the field's from the report, then add a single/simple new table and preview, still no data is showing.
Are there any logs inside crystal to investigate ? have tried ODBC.logs doesnt help as doesn't say what happens inside crystal reports after retrieving the data from database.
Thanks.
Zain
I've had this problem multiple times where my report comes up with empty fields. This may not be your cause, but what fixes it for me is to make sure that the dataset/table matches is referred to by the same name everyplace. In the xxxxxxDataset.xsd file, that table that's pictured should be the same name that's used in the function GetData() As System.Data.DataSet in your .NET object that uses the stored procedure to get the data. (You may call your function something other than GetData().) So try changing the ds.Tables(0).Tablename = "xxxxxxxTable" to match what the table in the xsd file is called.
I have an access project that is "linked" to a SQL database that now works like a charm. The last problem I solved was, making sure any Boolean fields be turned to bits with default of 0, and adding the TIMESTAMP in SQL due to the fact that ACCESS is not so much of a genius with record locking (so I was told) .
Now that I tried to connect direct to SQL server by using an ADODB.Recordset and setting the forms.recordset to the recordset, at the OnOpen event of the form, (this recordset runs a stored procedure in SQL, I get the data fine but get the error locking (write conflict) back.
This ADODB.Recordset cursorlocation is set to "adUseClient".
Obviously I no longer have the forms recordsource attached or assigned to the linked SQL table anymore.
Am I missing something? do I need to assign anything to the forms recordsource?
The Idea is trying to connect directly thru the use of stored procedures instead of linked tables.
thanks so much for any help.
The adding of timestamp is a VERY good idea. And do not confuse the term/name used timestamp to mean an actual date/time column. The correct term is "row version".
This issue has ZERO to do with locking. The REASON why you want this column added is because then Access will use that column to determine when the record is dirty, and more imporant figure out that the record been changed. If you omit this column, then access reverts to a column by column testing approach. Not only does this cause more network traffic, but worse for real type values, due to rounding, you can get the dredged this record has been changed by another user. But, it not been changed, and even columns with floating point values will cause access to error out with that changed record.
So, for all tables, and you even see the option included in the SSMA (the access to sql migration wizard that this option is available (and I believe it is a default).
So yes, it is HIGH but VERY high recommended that you include/add a rowversion column to all tables - this will help Access in a HUGE way.
And as noted, there is a long standing issue with bit fields that don't have a default setting. so, you don't want to allow bit fields to be added/created with a null value. So, ensure that there is a default value of 0 (you set this sql server side).
Ok, now that we have the above cleared up?
It not really all that clear as to why you want or need or are adopting a store procedure and code to load/fill up the form. You not see any better performance if you bind the form DIRECTLY to the linked table. Access will ONLY pull the reocrds you tell that form to load.
So, bind the form directly to the linked table. Then, you can launch/open the form say to once reocrd with this:
docmd.OpenForm "frmInvoices",,,"InvoiceNum = 123"
Now, you would of course change the above "123" to some variable or some way to prompt the user for what invoice to work on.
The invoice form will then load to the ONE record. So, even if the form bound (linked table) has 2 million rows? Only ONE record will come down the network pipe. So, all that extra work of a store procedure, creating a recordset and pulling it ? You will gain ZERO in terms of performance, but you are writing all kinds of code when it simply not required, and you not achieve any superior performance to the above one line of code that will automatic filter and ONLY pull down the record that meets the given criteria (in this example invoice number).
So:
Yes, all tables need a PK
Yes, all tables should have a rowversion (but it called a timestamp column - nothing to do with the actual time).
Yes, all bit fields need a default of 0 - don't allow null values.
And last but not least?
I don't see any gains in performance, or even any advantages of attempting to code your way though this by adopting store procedures and that of introducing reocrdset code when none is required, but worse will not gain you performance anyway.
I have performed this process numerous times with other Reports but this one Report is not working as it should.
Essentially, I am trying to point a report at a new server where the stored procedure is EXACTLY the same as on the previous server. I am using the Verify Database functionality to do this. But when I point at the new server and enter parameters, CR prompts me to re-map the fields. This would be only slightly annoying if the Map Fields window actually displayed the returned columns from the new server.
But, as you can see from the image, even with the 'Match type' unchecked, no columns from the stored procedure display to be mapped. I have clicked on every field in the report but none of them show any columns to map to.
I have also tried changing the Database Location first before trying to verify, but that doesn't make any difference.
Has anybody else seen this? Is there any sort of workaround?
I found my solution. Kinda dumb, really.
My stored procedure calls another stored procedure. I commented that call out and tried to Verify the Database and it worked.
Apparently Crystal Reports doesn't handle procedures that call other procedures very well when trying to map fields.
According to the searching I've done over the past couple of days, what I'm trying to achieve should be fairly straightforward but nothing that I've found has solved my problems. This is my first time at using Access, or SQL at all. Apologies in advance for the length of the question.
Essentially I need to pick up a value from one table and multiply it by another in the another table, and then store the result in the second table, via forms and subforms.
The Problem:
I'm attempting to create a database of projects, part of which is a quotation tool. The database has several tables covering all the required inputs for our project managers, most of which are linked to the PKs of their parent tables.
My current attempt has a form (frmJobDetails) giving the details of the each project (linked to tblJobs). This form has two subforms:
frmJobRolesSubform details who's working on the project in what role ( and, notably, their sale rate.
frmJobProcessesSubform details the tasks, who's allocated to which task and the estimated number of hours to complete.
Both subforms link to their own tables (tblJobs_Roles and tblJobs_Processes respectively).
frmJobProcessesSubform obtains the people working on the project and their roles from frmJobRolesSubform so the manager can allocate a person to a task on frmJobProcessesSubform. This is done via a combobox: cboRole.
So far, so good.
I'm needing to obtain the sale rate of the person working on the given task so that I can calculate the cost of the task. Specifically, I'd like a field on the subform to calculate the cost of the task and then store it in tblJobs_Processes.
My Attempts
I've attempted to build a query (qryProcessCost) that calls cboRole, either as an expression in the Field cell or in the Criteria cell ([Forms]![frmJobsProcessesSubform]![cboRole]).
I'm aware this can't successfully when the form isn't active, but I'm getting Access' request for input for [Forms]![frmJobsProcessesSubform]![cboRole] when selecting from the subform. The query runs successfully when example values are hardcoded into the query. The query should, obviously, only return a single value.
I've tried setting the ControlSource of a textbox to [qryProcessCost]![dblProcessCost] (where dblProcessCost is the calculated field), but this can't then write to the table (as far as I can deduce). Also, I get a #Name? error in the cell and I can't seem to get to the bottom of that.
I've tried setting the RecordSource property of a combobox to SELECT [qryProcessCost]![dblProcessCost] FROM [qryProcessCost], and the ControlSource to the relevant field of the table. While this would be a clunky solution, it actually doesn't work anyway as it fails to pick up the value of [Forms]![frmJobsProcessesSubform]![cboRole].
I've tried using an intermediate textbox to determine what value cboRole is passing, and I'm happy with that - the primary key of the role assigned in frmJobsRolesSubform.
The Question:
I'm guessing that I'm probably going to have to resort to VBA at this point to get what I want but I'm unfamiliar with the Access VBA structures (though I've used Excel VBA a fair bit).
Anyone got any ideas, hints, suggestions or pointers?
Cheers in advance,
Aaron
In case anyone else has a similar problem, I've posted my complete solution below:
I implemented Gene's correction to my references, which provided something, but the query wouldn't update when the fields on the form were changed. As I noted in the question, I also really wanted it to be a text box rather than a combo box for usability reasons but wasn't sure how to have a Record Source and Control Source for a text box.
I ended up going round in circles, via VBA and macros and several types of error and happened upon a suggestion to use a DLookUp here. I hadn't been able to get them to work for this particular problem before, but I managed to make it work this time. Specifically, I put the DLookUp in the following macro:
SetProperty
Control Name txtBudgetCost
Property Value
Value =DLookUp("[dblCostRate]","[tblJobs_Roles]","[pkJobs_RoleID]="[cboRole])*[txtBudgetHours]
This macro was used for the After Update event of the relevant fields on the subform.
Setting the value property of a field to a DLookUp meant that I could set the Control Source property of a the text box txtBudgetCost to the relevant field in the table, to obtain the desired behaviour.
Both cboRole and txtBudgetHours are fields on the same subform as the field txtBudgetCost.
The only problem with this solution is that, when the subform is viewed in the Datasheet view, a #Name? error is given for the new record row. I probably just need to enter some error handling somewhere, though I haven't given much thought for what it should be just yet.
Cheers,
Aaron
I am using Crystal Reports 8.0.1.0 and have an OLEDB connection set as "favourite".
We have several reports being run against a few stored procedures on the database.
Our database is an SQLExpress 2005 named instance.
One of the reports deals with balance, i.e. we have to provide a balance report for a specific company or set of companies.
The customer, however, has specifically asked us to have a separate section to be the last one for a specific economic account typology and in order to do this, we have to separate this one from the others which are instead displayed using two parallel subreports.
Hence our structure should be like follows:
GENERAL HEADING
PATRIMONIAL STATE
...data...
ECONOMIC COUNTS
...data...
THIRD-PARTY EFFECTS
...data...
The first two sections below the general heading are achieved with two parallel subreports, so now we have to display the third section.
Is it clear up to now? Well, as you may well be aware, CR subreports require you to set the database location, regardless if you have set one up already for main report.
The problem, however, is that if I try to set the location pointing to our stored procedure(which returns ALL the data for the balance report), the first time it will display the message in subject, and the second time again, but this time it'll also crash.
Our stored procedure has a parameter and both previous subreports(the ones in parallel) are set to the same SP and are working flawlessly.
This crash makes it impossible for me to work on the third section and I'm pretty much at loss as to what would be the best approach to solve the issue at hand.
Any ideas/suggestions?
I would love to receive your answers and I hope my problem was clear enough(I'm very willing to further delve into it for clarification if ever needed).
Thank you so much for your time,
Andrea Raimondi
Geez... changing the connection from OLEDB to SQLServer it correctly fetches the rowset and doesn't crash!
I am speechless.
Andrew