Replacing empty values with zeros - reporting-services

I know this question has been asked many times before, but having followed previous solutions I still can't resolve the issue:
I have a SSRS (2008R2) report, that displays data in a matrix. There is a horizontal column group containing values that may or may not exist: when the value doesn't exist, I'd like to replace the empty cell with a 0. Currently the report renders like:
and I'd like those empty cells to have 0's in them instead.
The cell expression was set to:
=Sum(Fields!number.Value)
so I tried
=iif (IsNothing(Sum(Fields!number.Value)),0,Sum(Fields!number.Value))
and
=iif (IsNothing(Fields!number.Value),0,Sum(Fields!number.Value))
and
=iif (Sum(Fields!number.Value)>0,Sum(Fields!number.Value),0)
... but the "empty" cells persist. I'm sure I'm doing something daft... but what?
EDIT: To illustrate my situation better, my query produces output (in SSMS) similar to:
File | outcomeID | number
A | Outcome1 | 2
A | Outcome2 | 1
B | Outcome2 | 2
C | Outcome1 | 1
D | Outcome3 | 2
... which would produce the outcome in SSRS of:
File | Outcome1 | Outcome2 | Outcome3
A | 2 | 1 |
B | 2 | |
C | 1 | |
D | | | 2
using a Column Group:
Even if I change the expression to be simply:
=999
I end up with
File | Outcome1 | Outcome2 | Outcome3
A | 999 | 999 |
B | 999 | |
C | 999 | |
D | | | 999
... i.e. lots of blank spaces.
EDIT2: I've uploaded a very small example .rdl file [REMOVED], using the example data above - it reproduces the issue

my first thought was a change to the stored procedure but since i had a similar report to test something on quickly i had an idea.
try this instead
=0+Sum(Fields!number.Value)

I tend to use the following (on SSRS 2005, however): =CInt(Fields!number.Value). It's possible to use other conversions, like CDbl, as well.
Alternatively, but a tiny bit longer, try =IIf(Fields!number.Value Is Nothing, 0, Fields!number.Value).

Related

Is there a way in SQL to create a new column that looks at the values in a column that shares multiple rows to determine the value in the new column?

My data looks similar to what I've attached.
I'm wanting to create a new column that looks at the appt# and any row associated with that appt to see if that appt had the procedure D0330 and marks it yes or no.
So for example B Bradley's appt 8210 did include the procedure D0330. So the new column would be marked yes for both lines 1 & 2 despite line 2 not having that specific procedure in it's row.
What would be the best way to go about doing this?
Data
You can't define a column of a table that auto-generates a value based on multiple rows, or a subquery, or anything like that. Generated columns can only be based on simple functions that reference columns within the same row.
But you can reference a window of rows in a query, and produce a column of that query result, even though the column is not persisted in the table.
SELECT *, MAX(CASE `procedure` WHEN 'D0330' THEN 'Yes' ELSE 'No' END)
OVER (PARTITION BY employee) AS `newcolumn`
FROM mytable;
+------+-----------+-----------+------+-----------+
| line | employee | procedure | apt | newcolumn |
+------+-----------+-----------+------+-----------+
| 1 | B Bradley | D0330 | 8210 | Yes |
| 2 | B Bradley | D1226 | 8210 | Yes |
| 3 | C Connor | D1457 | 1130 | No |
| 4 | D David | D0330 | 543 | Yes |
+------+-----------+-----------+------+-----------+
Window functions require MySQL 8.0.

FDQuery and OnCalcFields, get the previous line

Delphi 10.3.3
FireDAC: DBGrid / FDQuery / MySQL
VCL
Hi all,
I have a table with these fields
----------------------
| id | data |
----------------------
| 1 | 0=A;1=B;2=C |
| 2 | 2=Z |
| 3 | |
| 4 | 0=Y;1=X |
| 5 | |
| 6 | |
Each row of data represents only the change in the table
I would like this to be display in a DBGRID:
-----------------------
| id | C0 | C1 | C2 |
-----------------------
| 1 | A | B | C |
| 2 | A | B | Z |
| 3 | A | B | Z |
| 4 | Y | X | Z |
| 5 | Y | X | Z |
| 6 | Y | X | Z |
What I can do for now is only the following table:
-----------------------
| id | C0 | C1 | C2 |
-----------------------
| 1 | A | B | C |
| 2 | | | Z |
| 3 | | | |
| 4 | Y | X | |
| 5 | | | |
| 6 | | | |
To obtain this result, I create additional columns in the event FDQuery1.BeforeOpen
And in the event OnCreateFields, I fill each column but I don't know the previous row content,
So, how can I do to fill in the missing fields in the DBgrid?
Thanks
Franck
I think you mean OnCalcFields, rather than OnCreateFields.
What you need
is certainly possible, either server-side by deriving the necessary values from the prior
row using e.g. a SQL subquery or client-side using calculated fields. This answer is about doing it
client-side.
The problem with doing client-side calculations involving another dataset row is that
to do this you need to be able to move the dataset cursor during the OnCalcFields event. However, at the time, the DataSet will be in either dsCalcFields or dsInternalCalc state
and, while it is, you can't easily move to another row in the dataset. It is possible to do this, but
requires declaring a descendant dataset class (TMyFDQuery) so that you can access the SetTempState
necessary to do revert to the prior state after you've picked up the necessary info from the "other"
row and, if what you need involves more that one field, you need somewhere to store the values temporarily.
So doing it that way gets messy.
A much cleaner approach involves using functional similarity between FireDAC's datasets and TClientDataSets.
One of the nice features of TClientDatasSets is the ease with which you can move the dataset contents between
two CDSs simply by doing
CDS2.Data := CDS1.Data;
FireDAC datasets can do the same trick, but between any FD dataset types. So here is what I would do in your
situation:
Add an FDMemTable to your form/datamodule and copy the query data into it in the FDQuery's AfterOpen event like
this:
procedure TForm2.FDQuery1AfterOpen(DataSet: TDataSet);
begin
FDQuery1.DisableControls;
try
FDMemTable1.Data := FDQuery1.Data;
FDMemTable1.Open;
finally
FDQuery1.First;
FDQuery1.EnableControls;
end;
end;
The FDQuery1.First is to force it to re-do its calculated fields once the FDMemTable data is available
(during the initial FDQuery1.Open, it can't be, of course).
In the FDQuery's OnCalcFields event, use code like this to base the calculated fields'
values on values picked up from the prior row (if there is one of course, the first
row can't hae a "prior" row):
procedure TForm2.FDQuery1CalcFields(DataSet: TDataSet);
begin
if FDMemTable1.Active then begin
if FDMemTable1.Locate('ContactID', FDQuery1.FieldByName('ContactID').AsInteger, []) then begin
FDMemTable1.Prior;
if not FDMemTable1.Bof then begin
// Set FDQuery1's calculated fields that depend on prior row
FDQuery1.FieldByName('PriorRowID').AsInteger := FDMemTable1.FieldByName('ContactID').AsInteger;
end;
end;
end;
end;
In this example, my queried dataset has a ContactID primary key and the calculated value is simply the ContactID value from the prior row. In real life, of course, it
would be more efficient to use persistent field variables rather than keep calling FieldByName.
I suppose another possibility might be to use the CloneCursor method to obtain a lookup cursor
to access the "prior" row, but I've not tried that myself and it may not be possible anyway
(what happens about the calculated fields in the CloneCuror copy?).

SSIS Flat File Destination - Columns going out of sync when adding new column

Really hoping someone can help me with this 2008 SSIS BIDS issue. I am very new to the software so I am hoping it will be something simple!
I am attempting to use SSIS to retrieve data from an SQL table. My data flow consists of one OLE DB Source pointing directly to one Flat File Destination.
At the moment I can successfully retrieve 4 columns which display fine however when I attempt to add a fifth column (from data returned from SQL database) it appears to jumble everything up.
To elaborate the fifth column should contain a letter between “A – F” however instead of pulling this through from my results in the OLE Data Source it appears to be pulling through data from columns 1 – 4
EG before adding this extra column things look like this:
|----------|------------|-------------|--------|
| Column 1 |Column2 |Column3 |Column4 |
|----------|------------|-------------|--------|
|444456654 |10/01/2015 |User unable |JSMIT14 |
| | |to logout of | |
| | |app without | |
| | |crashing. | |
------------------------------------------------
However after adding the end column and mapping it accordingly everything seems to go out of sync, with added quotation marks:
|----------|------------|-------------|--------|-----------------------|
| Column 1 |Column2 |Column3 |Column4 |Column 5 |
|----------|------------|-------------|--------|-----------------------|
|444456654 |10/01/2015 |User unable |JSMIT14 |444456654”,”User |
| | |to logout of | |unable to logout of |
| | |app without | |app without |
| | |crashing. | |crashing.”,”JSMITH14 |
-----------------------------------------------------------------------
I was expecting it to pull through the data as I had mapped it and appear as below:
|----------|------------|-------------|--------|---------|
| Column 1 |Column2 |Column3 |Column4 |Column 5 |
|----------|------------|-------------|--------|---------|
|444456654 |10/01/2015 |User unable |JSMIT14 | F |
| | |to logout of | | |
| | |app without | | |
| | |crashing. | | |
----------------------------------------------------------
I add the extra column by selecting “Flat File Connection Manager” > “Advanced” > “New”.
I then map the SQL column to my new column by selecting “Flat File Destination” > “Mappings”
Please note if I select the data source and preview the SQL code all appears fine so I feel that something must be going wrong at the Flat File Destination stage.

How to replace substring in mysql where string is based on other table-column values

I have two mysql tables as
Component
+----+-------------------------+--------+
| OldComponentId | NewComponentId |
+----+-------------------------+--------+
| 15 | 85 |
| 16 | 86 |
| 17 | 87 |
+----+-------------------------+--------+
Formulae
+----+-------------------------+--------+
| id | formula_string |
+----+-------------------------+--------+
| 1 | A+15-16+17 |
| 2 | 16+15-17 |
+----+-------------------------+--------+
I want to replace value of formula_string on the basis of NewComponentId as
Formulae
+----+-------------------------+--------+
| id | formula_string |
+----+-------------------------+--------+
| 1 | A+85-86+87 |
| 2 | 86+85-87 |
+----+-------------------------+--------+
I have tried with following mysql query but its not working
update Formulae fr, Component comp set formula_string=REPLACE(fr.formula_string,comp.OldComponentId,comp.NewComponentId).
Please suggest the solutions
thanks.
There is no easy way to do this. As you observed in your update statement, the replacements don't nest. They just replace one at a time.
One thing that you can do is:
update Formulae fr cross join
Component comp
set formula_string = REPLACE(fr.formula_string, comp.OldComponentId, comp.NewComponentId)
where formula_string like concat('%', comp.OldComponentId, '%')
Then continue running this until row_count() returns 0.
Do note that your structure could result in infinite loops (if A --> B and B --> A). You also have a problem of "confusion" so 10 would be replaced in 100. This suggests that your overall data structure may not be correct. Perhaps you should break up the formula into separate pieces. If they are just numbers and + and -, you can have a junction table with the value and the sign for each component. Then your query would be much easier.

MySQL - IF something, THEN also select where

So, I have a confusing MySQL issue. I feel like I need to use some IF statements, but I'm really not sure how to implement them into this situation! First, consider the following query. It's simple:
SELECT *
FROM flow
INNER JOIN flow_strings
USING(node_id)
WHERE
(
flow.parent = 0
OR flow.parent = :user_flow
)
AND flow.source = 0
AND :input LIKE flow_strings.sql_regex
However, I need to expand it, and that's where I'm stuck. Thinking through this, I'm not really sure how to explain it, so following are the table structures, and then some examples.
TABLE flow
+---------+--------+--------+
| node_id | parent | source |
+---------+--------+--------+
| 1 | 0 | 0 |
+---------+--------+--------+
| 2 | 0 | 0 |
+---------+--------+--------+
| 3 | 1 | 1 |
+---------+--------+--------+
| 4 | 3 | 0 |
+---------+--------+--------+
TABLE flow_strings
+----------------+---------+-----------+
| flow_string_id | node_id | sql_regex |
+----------------+---------+-----------+
| 1 | 1 | fish |
+----------------+---------+-----------+
| 2 | 1 | wish |
+----------------+---------+-----------+
| 3 | 1 | *yes* |
+----------------+---------+-----------+
| 4 | 2 | *no* |
+----------------+---------+-----------+
| 5 | 2 | nay |
+----------------+---------+-----------+
| 6 | 3 | *herp* |
+----------------+---------+-----------+
[ ... ]
TABLE placeholder_variables
+-------------+--------+------+-------+
| variable_id | source | name | value |
+-------------+--------+------+-------+
| 1 | 0 | yes | sure |
+-------------+--------+------+-------+
| 2 | 0 | yes | yeah |
+-------------+--------+------+-------+
| 3 | 0 | no | nope |
+-------------+--------+------+-------+
| 4 | 1 | herp | derp |
+-------------+--------+------+-------+
NOW, here's what I need to happen based on :input.
"fish", "wish", "sure", or "yeah" ---SELECT flow.node_id 1
This is because "fish", "wish", and "*yes*" are all associated with flow.node_id 1. Note that *yes* is surrounded by asterisks, so instead of "yes" being interpreted literally, it instead draws the values from placeholder_variables.
"nope" or "nay" ---SELECT flow.node_id 2
This is because "*no*" and "nay" are associated with flow.node_id 2. Again, because of the asterisks, "no" is not interpreted literally, but "nope" matches because "no" is in the placeholder_variables table, even though "nope" is not in the flow_strings table.
"no" and "*no*" ---NO MATCH
Even though *no* is in flow_strings, it should not match because it has asterisks around it (and a corresponding placeholder_variable) which means it should not be interpreted literally, and so can only be evaluated by its corresponding placeholder variable's value(s).
"baby" ---NO MATCH
Even though "baby" does not have asterisks around it, it corresponds to flow.node_id 3, and that node's flow.source is 1.
"derp" ---NO MATCH
This is because placeholder_variables.source is 1 for *herp*, even though it is in the flow_strings table.
"*herp*" ---SELECT flow.node_id 4
Even though there are asterisks around *herp* in the flow_strings table, the corresponding placeholder_variable.source is 1.
** TO SUM UP **
No source = 1
Interpret placeholder_variables if the sql_regex is surrounded by asterisks, but only if the corresponding placeholder_variable's source is 0.
If source is 0, and no asterisks are present, interpret sql_regex literally.
I know that I can use MySQL's SUBSTRING() to work with the asterisks. I also know that, (as I am using PHP) I could theoretically split this into two queries, and then dynamically generate the second query by looping through the first. However, this would be both A) memory intensive, and B) sloppy.
So my question is this: Is it possible to do this using MySQL alone? If yes, how would you recommend I format it? You don't need to write the query for me, but if you could help me with some of the logic, I'd be very grateful! I have absolutely no idea what to try besides what I have already outlined, and I definitely don't want to do that.
Thanks!
You can use this solution:
SELECT a.*,
COALESCE(c.value, b.sql_regex) AS string #-- If there was a successful JOIN (sql_regex was a variable), then display the value of the "value" column in placeholder_variables, otherwise if the JOIN did not succeed (sql_regex was a literal value), just display sql_regex instead.
FROM flow a
JOIN flow_strings b ON a.node_id = b.node_id
LEFT JOIN placeholder_variables c #-- LEFT JOIN placeholder_variables on these conditions:
ON b.sql_regex LIKE '*%*' AND -- That sql_regex is a variable
REPLACE(b.sql_regex, '*', '') = c.name AND -- Match sql_regex up with the "name" column in placeholder_variables. We must replace the asterisks in sql_regex so that the values can match ("name" column do not contain asterisks)
c.source = 0
WHERE a.source = 0 AND
COALESCE(c.value, b.sql_regex) = :input -- If the string was interpreted as a placeholder variable, make the condition on the interpreted value in the placeholder_variables table ("name" column), otherwise, just make the condition on the sql_regex column.
SQLFiddle Demo