iReport not accepting SQL SUM function - mysql

iReport does not seem to accept the normal SQL SUM function and I am having a hard time figuring out a way around this.
I am trying to use SUM(qtytofulfill.SOITEM - qtyfulfilled.SOITEM) AS qty and it does not seem to like that or me simply adding the variables and saying SUM(qtytofulfill - qtyfulfilled) AS qty.
This does not seem to be a syntax error but iReport simply will not accept it as an SQL statement. I am posting a picture of me attempting to use this SQL statement and the error it also gives. Any help on what I am doing or even what I actually should be using , specifically, for iReport is greatly appreciated.
Thanks!
-Colt

This will work fine,
In standard SQL (but not MySQL), when you use GROUP BY, you must list
all the result columns that are not aggregates in the GROUP BY clause.
SELECT
SOITEM.'QTYFULFILLED' AS QTYFULFILLED,
SOITEM.`QTYTOFULFILL` AS QTYTOFULFILL,
SOITEM.`SOID` AS SOITEM_SOID,
SUM(SOITEM.`QTYFULFILLED`) AS Sum_Quantity_Fullfilled,
SUM(SOITEM.`QTYTOFULFILL`) AS Sum_Quantity_to_Fullfill,
(SUM(SOITEM.`QTYFULFILLED`) - SUM(SOITEM.`QTYTOFULFILL`)) AS QTY,
SO.`ID` AS SO_ID
FROM
`SO` SO INNER JOIN `SOITEM` SOITEM ON SO.`ID` = SOITEM.`SOID`
GROUP BY SOITEM.'QTYFULFILLED',SOITEM.`QTYTOFULFILL`,SOITEM.`SOID`,SO.`ID`
Hope this helps.

I believe it's treating the 2 column names inside sum as variables, not table columns

I would suggest to:
1) check your SQL syntax since you're not grouping on all the non-aggregate columns (you're grouping just on SO_ID)
2) eventualy check the arguments of your sum: alias instead of fields

Since you tagged this jasper report and it seems that you like both the value of the single record and the sum of all records in your report I would suggest this.
Select your records without any sum values.
SELECT
SOITEM.'QTYFULFILLED' AS QTYFULFILLED,
SOITEM.`QTYTOFULFILL` AS QTYTOFULFILL,
SOITEM.`SOID` AS SOITEM_SOID,
SO.`ID` AS SO_ID
FROM
`SO` SO INNER JOIN `SOITEM` SOITEM ON SO.`ID` = SOITEM.`SOID`
Define the fields. es
<field name="QTYFULFILLED" class="java.lang.Double">
<fieldDescription><![CDATA[]]></fieldDescription>
</field>
<field name="QTYTOFULFILL" class="java.lang.Double">
<fieldDescription><![CDATA[]]></fieldDescription>
</field>
Define the sum variables
<variable name="SUM_QTYFULFILLED" class="java.lang.Double" calculation="Sum">
<variableExpression><![CDATA[$F{QTYFULFILLED}]]></variableExpression>
</variable>
<variable name="SUM_QTYTOFULFILL" class="java.lang.Double" calculation="Sum">
<variableExpression><![CDATA[$F{QTYTOFULFILL}]]></variableExpression>
</variable>
And thats it!, if you like to output the difference your QTA to an textfield
<textField evaluationTime="Report">
<reportElement x="10" y="4" width="100" height="20" uuid="7aa31c20-bd5f-4222-9744-4206d096bb90"/>
<textElement>
<paragraph lineSpacing="Single"/>
</textElement>
<textFieldExpression><![CDATA[NumberFormat.getNumberInstance().format($V{SUM_QTYFULFILLED}.doubleValue()-$V{SUM_QTYTOFULFILL}.doubleValue())]]></textFieldExpression>
</textField>
remember to set evaluation time to report (since it needs to finish calculate the variables before printing it)

Related

SSRS reports using Report Parameter in two datasets

I'm fixing some really old SSRS reports. I'm doing it by editing the rdl files directly in notepad++ which so far has been working well since the format is easily readable XML.
However, I have run into a problem trying to use the same ReportParameter in two datasets.
I have this in my rdl file:
<ReportParameters>
<ReportParameter Name="Fromdate">
<DataType>DateTime</DataType>
<Prompt>From date:</Prompt>
</ReportParameter>
<ReportParameter Name="Todate">
<DataType>DateTime</DataType>
<Prompt>To date:</Prompt>
</ReportParameter>
</ReportParameters>
This makes it so that before the report is opened, the user enters two dates that are then used in the queries that show data in the report.
The first query is working well with this. It's an Oracle query and looks like this:
<DataSet Name="OracleDS">
<Query>
<DataSourceName>Oracle</DataSourceName>
<QueryParameters>
<QueryParameter Name="Fromdate">
<Value>=Parameters!Fromdate.Value</Value>
<rd:UserDefined>true</rd:UserDefined>
</QueryParameter>
<QueryParameter Name="Todate">
<Value>=Parameters!Todate.Value</Value>
<rd:UserDefined>true</rd:UserDefined>
</QueryParameter>
</QueryParameters>
<CommandText>SELECT myColumn FROM myTable WHERE myDate BETWEEN :Fromdate AND :Todate</CommandText>
</Query>
<Fields>
<Field Name="myColumn">
<DataField>MyColumn</DataField>
<rd:TypeName>System.String</rd:TypeName>
</Field>
</Fields>
</DataSet>
Getting the :Fromdate and :Todate works in this query. However, when I try to do the same in my other query, which is an MSSQL query, I can't open the report because SSRS tells me there's a problem with the query. Here's what the second dataset looks like:
<DataSet Name="MSSQLDS">
<Query>
<DataSourceName>MSSQL</DataSourceName>
<CommandText>SELECT myColumn FROM myOtherTableOnAnotherDatabase WHERE myDate BETWEEN :Fromdate AND :Todate</CommandText>
</Query>
<Fields>
<Field Name="myColumn">
<DataField>myColumn</DataField>
<rd:TypeName>System.String</rd:TypeName>
</Field>
</Fields>
</DataSet>
Seems pretty straight forward. I have even tried switching places between the two datasets in the file, but the Oracle dataset works while the MSSQL dataset doesn't.
I thought maybe I need to add ' around the dates, so I tried some stuff like:
[...]
WHERE myDate BETWEEN ':Fromdate' AND ':Todate'
[...]
WHERE myDate BETWEEN '& :Fromdate &' AND '& :Todate &'
DECLARE #startdate datetime DECLARE #enddate datetime
SET #startdate = CAST(:Fromdate as datetime)
SET #enddate = CAST(:Todate as datetime)
SELECT myColumn FROM myTable
WHERE myDate BETWEEN #startdate AND #enddate
But SSRS keeps telling me that there's an error getting the data for this dataset. It works if I hard code the dates in, like so:
<CommandText>SELECT myColumn FROM myOtherTableOnAnotherDatabase WHERE myDate BETWEEN '2020-01-01' AND '2020-01-31'</CommandText>
How can I use the same report parameters in the command texts of two datasets?
Just as I was about to post my question I realized that I was assuming that the report parameter should be passed with :ParameterName since that's how it was done for the Oracle part (and I'm not super familiar with Oracle syntax since I've been working mostly with MSSQL in the past). So I changed : to # for the MSSQL query and it worked:
WHERE myDate BETWEEN #Fromdate AND #Todate
D'oh!

How to use the CSV query language?

In JasperSoft Studio or iReport, how do you query on csv data? It has an option to do CSV query language but I cannot find any proper documentation or instructions on how it works.
I need to do group by and add conditional parameters without the need to transfer it first into a database.
The JRCsvQueryExecuter lets you sort and filter data from a cvs file
The sort command can be done on single or multiple fields.
<sortField name="name"/>
<sortField name="city" order="Descending"/>
The filtering is done by the filterExpression
<filterExpression><![CDATA[$P{IncludedStates}.contains($F{state}) ? Boolean.TRUE : Boolean.FALSE]]></filterExpression>
You can not use a normal sql statement but with these 2 properties, you are fairly close to order by and where. Specially since jasper reports have build in support for sum, avg (through variables) and the group by through groups.
<group name="YourGroup">
<groupExpression><![CDATA[$F{fieldToGroupOn}]]></groupExpression>
...the group bands ..
</group>
You can find a full running sample in the jasper reports distribution under demo\samples\csvdatasource\reports\CsvQueryExecuterReport.jrxml, this is the sample reference

How to handle complex conditional where clauses in mysql

Based on a variety of optional user inputs, I need to modify the structure of the where clause in query (not just dynamic values, but dynamic structure).
Examples.. if they select a customerID, then don't use the branchID filter, but if they select an empID then use both empID and branchID filters. There are more criteria that are used as well, thats just an example.
I could build all the logic into the where clause using CASE statements, but I'm guessing that wouldn't be very well optimized? I know I could dynamically build the sql statement within a stored proc, and i could use prepared statements as well... but that seems sloppy? Is there another method I'm not thinking of?
The usual approach is dynamically building the query in the layer that handles the user input. In case you do not use a high level language in front of your database, this means resorting to a stored procedure indeed, and this might look a bit dirty indeed - I too find this language quite awkward.
A pure SQL solution does not have too much of an overhead, since constant-based conditions will be optimized away quite efficiently (user input is constant when the query starts).
I have typically done what you are doing using bind variables and a conditional query, like so:
SELECT ...
FROM table
WHERE ...(put your where clause elements common to both cases here)
AND ((? = 'value1'
AND ...
AND ...
) OR
(? = 'value2'
AND ...
AND ...
))
GROUP BY ...
ORDER BY ...
? is the bind variable syntax for MySQL -- see Listing 23 here for a small example. In this case, bind vars 1 and 2 would actually be set to the same value.
You can also do the same sort of thing with a CASE statement.
mybatis dynamic sql may helps you。
<select id="findActiveBlogLike"
resultType="Blog">
SELECT * FROM BLOG WHERE state = ‘ACTIVE’
<choose>
<when test="title != null">
AND title like #{title}
</when>
<when test="author != null and author.name != null">
AND author_name like #{author.name}
</when>
<otherwise>
AND featured = 1
</otherwise>
</choose>
</select>

MySQL & ColdFusion confusion

I have a query that was created to retrieve some data from a MySQL server and the query works great when running it directly on the server. When I run the query through a program like Sequel Pro it retrieves the data just fine as well. However, when inserted into a ColdFusion .cfc function, it retrieves all of the data except the timestamp field. I can't figure out why for the life of me. Here is the query followed by the CF Function.
SELECT tbl_names.*, max(tbl_timestamps.tstamp)
FROM tbl_names LEFT JOIN tbl_timestamps
ON tbl_names.name = tbl_timestamps.name
GROUP BY tbl_timestamps.name
<cffunction name="recent_timestamp" output="false" access="remote" returntype="any" >
<cfset var qAllItems="">
<cfquery name="qAllItems" datasource="TimeClock">
SELECT tbl_names.*, max(tbl_timestamps.tstamp)
FROM tbl_names LEFT JOIN tbl_timestamps
ON tbl_names.name = tbl_timestamps.name
GROUP BY tbl_timestamps.name
</cfquery>
<cfreturn qAllItems>
</cffunction>
When I run the application, when the .cfc function is called it pulls all of the data except the time stamps. Here is the error that Flash Builder gives me:
"The returned object contains an invalid property name "max(tbl_timestamps.timestamp)". If you are using a database query which uses a group function, then try using an alias in the query for this group function. Any thoughts on how I can fix this? I've tried just about everything I could find. Thanks in advance!
Just give alias for max(tbl_timestamps.tstamp) and it should work. I guess you are working on flex/flash project where you are calling CFC function remotely. Actually this is not an ColdFusion error but Flex/flash build not able to parse query with column name max(tbl_timestamps.tstamp) so giving alias will solve this issue.
Your query may look like below.
SELECT tbl_names.*, MAX(tbl_timestamps.tstamp) AS maxtstamp
FROM tbl_names LEFT JOIN tbl_timestamps
ON tbl_names.name = tbl_timestamps.name
GROUP BY tbl_timestamps.name
I'm surprised the query doesn't error out whenever you run it because your select clause has tbl_names.* while your group by clause has tbl_names.name. To fix it, change one of those so they match.
As far as an alias for max(tbl_timestamps.tstamp) goes, while you don't necessarily need one for the query to run in ColdFusion, you will need one if you want to do anything with that field, such as display it.

XPath to check if all provided pairs of elements exist for an entry

I have the following XML stored in an XML field in a SQL Server 2008 database.
<attributes>
<attribute>
<key>animal</key>
<value>rat</value>
</attribute>
<attribute>
<key>color</key>
<value>black</value>
</attribute>
</attributes>
I'm able to select all the entries from the table which have an 'animal' key with a value of 'rats' with the following xpath in sql.
SELECT *
FROM XmlEvents
WHERE Attributes.exist('/attributes/attribute[key="animal" and value="rat"]') = 1
How would I check for matches with multiple attributes?
I'm trying to find rows where: (Key=Animal & Value=Rat) AND (Key=Color & Value=Black).
(Yes, I could put another .exist with an AND in my WHERE clause but I'm trying to avoid that)
Bonus points if you can lead me in the right direction to make this some-what dynamic. I would love to have a stored procedure or function which could somehow take a list of Key/Value pairs and find all the rows which match everything provided.
XPath allows nested predicates and multiple predicates. You could write
/attributes[attribute[key="animal" and value="rat"]][attribute[key="color" and value="black"]]
or equivalently, but somewhat shorter
/attributes[attribute[key="animal"]/value="rat" and attribute[key="color"]/value="black"]