My Power Query expression is mostly a SQL query, taking advantage of query folding with a Snowflake SQL database. My where clause references two parameters that an end user sets in slicers:
WHERE Time BETWEEN '" & Date.ToText(DateTime.Date(StartTimeParameter)) & "' AND '" & Date.ToText(DateTime.Date(EndTimeParameter)) & "'
How can I require that the user selects the slicer/parameter value before the SQL is executed? Currently the SQL executes when the report is opened, and again when the parameter is changed. Perhaps I can make better default values, but most users will still need to adjust the slicers/parameters. The full SQL is complex and has a noticeable load time. I have tried making the two parameters optional, but the Power Query expression becomes invalid:
Expression.Error: We cannot convert the value null to type Text.
Related
I'm using Pentaho PDI 7.1. I'm trying to convert data from Mysql to Mysql changing the structure of data.
I'm reading the source table (customers) and for each row I've to run another query to calculate the balance.
I was trying to use Database value lookup to accomplish it but maybe is not the best way.
I've to run a query like this to get the balance:
SELECT
SUM(
CASE WHEN direzione='ENTRATA' THEN -importo ELSE +importo END
)
FROM Movimento WHERE contoFidelizzato_id = ?
I should set the parameter taking it from the previous step. Some advice?
The Database lookup value may be a good idea, especially if you are used to database reasoning, but it may result in many queries which may not be the most efficient.
A more PDI-ish style would be to make the query like:
SELECT contoFidelizzato_id
, SUM(CASE WHEN direzione='ENTRATA' THEN -importo ELSE +importo END)
FROM Movimento
GROUP BY contoFidelizzato_id
and use it as the info source of a Lookup Stream Step, like this:
An even more PDI-ish style would be to divert the source table (customer) in two flows : one in which you keep the source rows, and one that you group by contoFidelizzato_id. Of course, you need a formula, or a Javascript, or to put a formula in the SQL of the Table input to change the sign when needed.
Test to know which strategy is better in your case. You'll soon discover that the PDI is very good at handling large data.
I want to generate SQL queries from user input for inserting some data into a database.
The user may input anything. Is there a way in Qt to convert such user inputs in string-type values fields?
"The user may input anything."
That doesn't give us much to go by, but I can give you an example of how I would set up a basic insert query.
// I assume you already have a QSqlDatabase object called 'db'
QSqlQuery query(db);
QString s = "INSERT INTO table (colA, colB) VALUES (:valA, :valB);"
query.prepare(s);
// You only need to prepare the query once
// To actually insert values into colA & colB, do this:
query.bindValue(":valA", QString("stuff to put in colA"));
query.bindValue(":valB", QString("other stuff for colB"));
query.exec();
query.finish(); // you probably don't even need this
The bindValue method takes a QVariant as its second argument (I used strings in my example, but you could use anything supported by the variant type). You just have to make sure the type of the values makes sense for the relevant columns in your database.
Also, I'm using the syntax from PostgreSQL for my example. I think it's standard, but you may need to change the parameter binding (the :valA :valB stuff) to match what your db engine expects.
I've been given a project that uses AngularJS and ColdFusion as a Service. I understand Angular but I've never worked with ColdFusion before. Within the CFFunction Tag in a ColdFusionComponent I have some complex SQL that is being generated. In addition to the actual data being returned from the Service I would like to have the service return the actual text of the SQL executed. Can someone tell me how this can be done?
From the comments
In order to get the SQL statement that was executed you can use the result attribute of the <cfquery> tag. When you include that attribute then ColdFusion will return more information about the query including the SQL statement that was executed. See the docs here under the "usage" section (about midway down the page) for more information.
From the referenced documentation:
The cfquery tag also returns the following result variables in a structure. You can access these variables with a prefix of the name you specified in the result attribute. For example, if you assign the name myResult to the result attribute, you would retrieve the name of the SQL statement that was executed by accessing #myResult.sql#. The result attribute provides a way for functions or CFCs that are called from multiple pages, possibly at the same time, to avoid overwriting results of one call with another. The result variable of INSERT queries contains a key-value pair that is the automatically generated ID of the inserted row; this is available only for databases that support this feature. If more than one record was inserted, the value can be a list of IDs. The key name is database-specific.
Variable name Description
result_name.sql The SQL statement that was executed.
result_name.recordcount Number of records (rows) returned from the query.
result_name.cached True if the query was cached; False otherwise.
result_name.sqlparameters An ordered Array of cfqueryparam values.
result_name.columnList Comma-separated list of the query columns.
result_name.ExecutionTime Cumulative time required to process the query.
result_name.IDENTITYCOL SQL Server only. The ID of an inserted row.
result_name.ROWID Oracle only. The ID of an inserted row. This is not the
primary key of the row, although you can retrieve rows
based on this ID.
result_name.SYB_IDENTITY Sybase only. The ID of an inserted row.
result_name.SERIAL_COL Informix only. The ID of an inserted row.
result_name.GENERATED_KEY MySQL only. The ID of an inserted row. MySQL 3 does not
support this feature.
result_name.GENERATEDKEY Supports all databases. The ID of an inserted row.
To protect against sql injection, I read in the introduction to ColdFusion that we are to use the cfqueryparam tag.
But when using stored procedures, I am passing my variables to corresponding variable declarations in SQL Server:
DROP PROC Usr.[Save]
GO
CREATE PROC Usr.[Save]
(#UsrID Int
,#UsrName varchar(max)
) AS
UPDATE Usr
SET UsrName = #UsrName
WHERE UsrID=#UsrID
exec Usr.[get] #UsrID
Q: Is there any value in including cfSqlType when I call a stored procedure?
Here's how I'm currently doing it in Lucee:
storedproc procedure='Usr.[Save]' {
procparam value=Val(form.UsrID);
procparam value=form.UsrName;
procresult name='Usr';
}
This question came up indirectly on another thread. That thread was about query parameters, but the same issues apply to procedures. To summarize, yes you should always type query and proc parameters. Paraphrasing the other answer:
Since cfsqltype is optional, its importance is often underestimated:
Validation:
ColdFusion uses the selected cfsqltype (date, number, etcetera) to validate the "value". This occurs before any sql is ever sent to
the database. So if the "value" is invalid, like "ABC" for type
cf_sql_integer, you do not waste a database call on sql that was never
going to work anyway. When you omit the cfsqltype, everything is
submitted as a string and you lose the extra validation.
Accuracy:
Using an incorrect type may cause CF to submit the wrong value to the database. Selecting the proper cfsqltype ensures you are
sending the correct value - and - sending it in a non-ambiguous format
the database will interpret the way you expect.
Again, technically you can omit the cfsqltype. However, that
means CF will send everything to the database as a string.
Consequently, the database will perform implicit conversion
(usually undesirable). With implicit conversion, the interpretation
of the strings is left entirely up to the database - and it might
not always come up with the answer you would expect.
Submitting dates as strings, rather than date objects, is a
prime example. How will your database interpret a date string like
"05/04/2014"? As April 5th or a May 4th? Well, it depends. Change the
database or the database settings and the result may be completely
different.
The only way to ensure consistent results is to specify the
appropriate cfsqltype. It should match the data type of the target
column/function (or at least an equivalent type).
I have been searching for a while on how to get the generated auto-increment ID from an "INSERT . INTO ... (...) VALUES (...)". Even on stackoverflow, I only find the answer of using a "SELECT LAST_INSERT_ID()" in a subsequent query. I find this solution unsatisfactory for a number of reasons:
1) This will effectively double the queries sent to the database, especially since it is mostly handling inserts.
2) What will happen if more than one thread access the database at the same time? What if more than one application accesses the database at the same time? It seems to me the values are bound to become erroneous.
It's hard for me to believe that the MySQL C++ Connector wouldn't offer the feature that the Java Connector as well as the PHP Connector offer.
An example taken from http://forums.mysql.com/read.php?167,294960,295250
sql::Statement* stmt = conn->createStatement();
sql::ResultSet* res = stmt->executeQuery("SELECT ##identity AS id");
res->next();
my_ulong retVal = res->getInt64("id");
In nutshell, if your ID column is not an auto_increment column then you can as well use
SELECT ##identity AS id
EDIT:
Not sure what do you mean by second query/round trip. First I thought you are trying to know a different way to get the ID of the last inserted row but it looks like you are more interested in knowing whether you can save the round trip or not?
If that's the case, then I am completely agree with #WhozCraig; you can punch in both your queries in a single statement like inser into tab value ....;select last_inserted_id() which will be a single call
OR
you can have stored procedure like below to do the same and save the round trip
create procedure myproc
as
begin
insert into mytab values ...;
select last_inserted_id();
end
Let me know if this is not what you are trying to achieve.