Generally people use the default option that Spotfire gives. Connect to the DB and pull the set of columns that you need and create an Information Link and load the data to Spotfire.
However, I am using SQL Query to fetch data to Spotfire. I am creating a table similar to Views, and writing a simple stored procedure to pull the data:
Create procedure ProcA(In Start_Date date, IN End_Date date, In Site_Name text)
Begin
SELECT * FROM TableA where day between Start_Date and End_Date and
site_name = Site_Name;
This works fine if I am not using site name filtering.
The Information Links helps in filtering the date properly. But when it comes to Site Name, nothing works.
There are 2 requirements:
Is it possible to give a drop-down just like how filter comes for Date
How to pass multiple site names to pull only those sites into the Spotfire file
TL;DR: There are better ways to do this; if it's just for the column names, I don't think it's worth it to do part 2, since it's easy enough to change the sql in the information link, but it's possible.
Okay, I will try (read: fail) not to be too long-winded.
1) Is it possible to do a drop-down for dates? Yes. The easiest way to do this would be to pull a data table with all of your date choices available for the end user. Here's an example finding a list of better way to generate months/year table Remember when creating your dropdownlist that your Document Property has to have the Data type "Date", and then you should be able to set property values through Unique Values in column against your date column from the new data, the same as you would do for a string drop-down list.
If you have a small subset of specific dates to choose from, this probably isn't too bad. If the drop down list gets longer, your end-users can type in the date they're looking for to speed up their search (though in my experience, a lot of them will scroll through until they find the date they're looking for).
While this is perfectly acceptable, if you're at all comfortable adding javascript, I'd personally recommend using a Popup Calendar These are fairly straightforward for end-users, and can allow them to use the calendar or type it themselves. (And if they type something that isn't a date in, it's even kind enough to inform them with red letters and an exclamation mark that they haven't typed an actual date)
2) How to pass multiple site names to pull only those sites into the Spotfire file
Hoo boi, where to start.
Step one: How do you want to select your list of Site Names? I'm going to go ahead and assume you have a data table with a list of distinct Site Names.
Your next choice is how to let your user select which Site Names they want. General options are using a List Box Filter, displaying a table and using marked rows, or providing a text area where the user can type their selections themselves.
When I needed to do this, I did a combo of a data table and a text area, so that's what I'm going to describe here.
I start off by providing the user with a text area, formatted to "specific size" with a larger than usual height to prompt that, yes, they are allowed to type multiple rows. If they know the values they're looking for, they can type them in manually, or copy paste from an excel file, etc.
If they don't know what they're looking for, the list of Site Names would be in a Table displayed for the user, where they can then mark the rows they want on the visualization and push a button which will do a cursor through the list of marked Site Names, concatenate them together, and put them in the text box previously mentioned (Note: if you don't want to let them enter their list manually, you can leave off the text area, combine these next two pieces of code, and throw it straight into the SpecialFilterProperty).
Please note that cursors are slow; if you have more than a few thousand rows to cycle through, this may stall out for a few seconds.
Code for the button:
from Spotfire.Dxp.Application.Visuals import CrossTablePlot
from Spotfire.Dxp.Data import IndexSet
from Spotfire.Dxp.Data import RowSelection
from Spotfire.Dxp.Data import DataValueCursor
from Spotfire.Dxp.Data import DataSelection
TextFltr = ""
crossSource = Document.Data.Tables["Distinct_SiteNames"]
##Get a Row Count
rowCount = Document.Data.Tables["Distinct_SiteNames"].RowCount
##Index Set of all our rows
rowIndexSet=Document.ActiveMarkingSelectionReference.GetSelection(Document.Data.Tables["Distinct_SiteNames"]).AsIndexSet()
allRows = IndexSet(rowCount,True)
if rowIndexSet.IsEmpty != True:
allRows = rowIndexSet
colCurs = DataValueCursor.CreateFormatted(crossSource.Columns["Site_Name"])
##Optional: Loop through to determine average value
colTotal = ''
for row in crossSource.GetRows(allRows, colCurs):
colTotal += ', ' + colCurs.CurrentValue
if TextFltr == "":
TextFltr += colTotal[2:]
else:
TextFltr += colTotal
Document.Properties["SelectedSiteNames"] = TextFltr
from System.Collections.Generic import Dictionary
from Spotfire.Dxp.Application.Scripting import ScriptDefinition
import clr
scriptDef = clr.Reference[ScriptDefinition]()
Document.ScriptManager.TryGetScript("Change Special Filter Value", scriptDef)
params = Dictionary[str, object]()
Document.ScriptManager.ExecuteScript(scriptDef.ScriptCode, params)
At the bottom it references a second script; this is the script attached to the button that parses through the text area when the user wants to submit their selections and refresh the data table.
The General Code I've used is here, script titled "Change Special Filter Value", which allows delimiting by newline, tabs, commas, quotes, and a few others. Feel free to add or subtract here, depending on your user-base's needs.
strVals = Document.Properties["SelectedSiteNames"]
lst = ""
cnt = 0
x = 0
y = 0
z = 0
for letter in strVals:
if y == 1:
if letter == " ":
lst = lst + "'" + strVals[x:z] + "', "
y = 0
elif letter == ",":
lst = lst + "'" + strVals[x:z] + "', "
y = 0
elif letter == "\n":
lst = lst + "'" + strVals[x:z] + "', "
y = 0
elif letter == "\r":
lst = lst + "'" + strVals[x:z] + "', "
y = 0
elif letter == "'":
lst = lst + "'" + strVals[x:z] + "', "
y = 0
elif letter == '"':
lst = lst + "'" + strVals[x:z] + "', "
y = 0
elif letter == '\t':
lst = lst + "'" + strVals[x:z] + "', "
y = 0
else:
if letter <> " " and letter <> "," and letter <> "\n" and letter <> "\r" and letter <> "'" and letter <> '"' and letter <> "\t":
if y == 0:
cnt += 1
print letter
x = z
y = 1
z += 1
if y == 1:
lst = lst + "'" + strVals[x:z] + "', "
print lst
lst = lst.upper()
if len(lst) > 0:
lst = lst[1:len(lst) - 3]
Document.Properties["SpecialFilterValue"] = lst
Step one is now complete! You have a list of all your selected site names in a property that you can now pass to your stored procedure.
Note: I believe there's a limit to the number of characters Spotfire can pass through a string value. In my previous testing, I think it's been over 500,000 characters (it's been a while, so I don't remember exactly), so you have a lot of leeway, but it does exist, and depending on which data source you're using, it may be lower.
Step Two: Alter the stored Procedure
Your stored procedure will basically be something along the lines of this:
Create procedure ProcA(In Start_Date date, IN End_Date date, In Site_Name text)
Begin
DECLARE #Script nvarchar(max) =
N'
Select * from TableA where day between Start_Date and End_Date and Site_Name in (' + #Site_Name + ') '
EXECUTE (#Script)
Downright easy in comparison!
(No loop after all! The bizarre use case I was remembering doesn't apply here, unless you're also using a data base that doesn't allow you to pass parameters directly...)
I have an Excel file that loosely resembles the following format:
I'll explain the next step of the SSIS element first as the column names are not "important" as I am un-pivoting the data in a data flow to start getting it usable:
The issue is, the file will be updated - years and quarters will be removed (historical), new ones added to replace the old ones. That means, as we all know, the metadata on a data flow is broken.
The cell range and position etc. will always remain the same.
Is there a way it can be handled in a data flow with the column names (2016q1) being fluid?
Thanks
You're going to like this as it also does the pivot:
Using C# Script component source:
Add namespace:
Using System.Data.OleDb;
Add your 4 output columns and select data types:
Add code to new row section.
public override void CreateNewOutputRows()
{
/*
Add rows by calling the AddRow method on the member variable named "<Output Name>Buffer".
For example, call MyOutputBuffer.AddRow() if your output was named "MyOutput".
*/
string fileName = #"C:\test.xlsx";
string SheetName = "Sheet1";
string cstr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + fileName + ";Extended Properties=\"Excel 12.0;HDR=YES;IMEX=1\"";
OleDbConnection xlConn = new OleDbConnection(cstr);
xlConn.Open();
OleDbCommand xlCmd = xlConn.CreateCommand();
xlCmd.CommandText = "Select * from [" + SheetName + "$]";
xlCmd.CommandType = CommandType.Text;
OleDbDataReader rdr = xlCmd.ExecuteReader();
//int rowCt = 0; //Counter
while (rdr.Read())
{
for (int i = 2; i < rdr.FieldCount; i++) //loop from 3 column to last
{
Output0Buffer.AddRow();
Output0Buffer.ColA = rdr[0].ToString();
Output0Buffer.ColB = rdr[1].ToString();
Output0Buffer.FactName = rdr.GetName(i);
Output0Buffer.FactValue = rdr.GetDouble(i);
}
//rowCt++; //increment counter
}
xlConn.Close();
}
If the columns remain in order, then you can skip header rows and select 1st row does not contain headers.
I want to pick the word "aaaaa.com" to a new column from the text " Next to each other with 703125 ABC: QWER => null - aaaaa.com . [VBN Res ID = 745075267#1(1/2)] Room 1 Comment: No meal is included in this room rate. " which comes in a 1 column in SSRS.
It is probably easier to output it as 2 columns in the dataset... but if you can't then the second option would be to use VB code.
Right click on the space behind your code and click 'Report Properties'.
Then in the Code section paste this:
Function SplitText(text As String, column As Int16) As String
If (column = 1) Then
Return text.Substring(0, text.Substring(0, text.IndexOf(".com") + 4).LastIndexOf(" "))
Else
Return text.Substring(text.Substring(0, text.IndexOf(".com") + 4).LastIndexOf(" ") + 1)
End If
End Function
Then in your report use this expression for the first column:
=Code.SplitText(Fields!text.Value,1)
and this for the second
=Code.SplitText(Fields!text.Value,2)
and you have your result!
EDIT
Or if you just want the email address on it's own use this code:
Function GetEmail(text As String) As String
Dim Result As String
Result = text.Substring(text.Substring(0, text.IndexOf(".co") + 3).LastIndexOf(" ") + 1)
Result = Result.Substring(0, Result.IndexOf(" "))
Return Result
End Function
What could be wrong with this select statement? I get an error called incorrect syntax near 'A'.
Since I am more used to write queries in postgreSQL, my guess is that MySQL has a bit different syntax.
cmd.CommandText = "WITH CurrentStop AS (SELECT[Stop Id] FROM Stops WHERE[Route Id] = " +
routeId + "AND Serial = " + stopsDriven + ")" +
"SELECT A.Firstname, A.Lastname, B.Make, B.Capacity, B.Route, D.Name" +
"FROM Driver A, Bus B, CurrentStop C, Stop D" +
"WHERE A.Id = " + row[0] + "AND B.[Bus Id] = " + row[1] + "AND C.[Stop Id] = D.[Stop Id]";
By the way, all inputs are in system only so no SQL injection could possibly happen.
Print out the query before trying to execute it and examine it closely. This solves a large chunk of the "what's wrong with my dynamically generated query?" style questions we see here.
For example, I'd be wary of the lack of space between (not necessarily an exhaustive list, these are just the ones I noticed):
routeId and the following AND;
row[0] and the following AND;
row[1] and the following AND;
D.Name and the following FROM; and
Stop D and the following WHERE.
Those last two are definitely problematic since, while it is possible the variables may end in a space (though unusual), the fixed strings certainly don't. And both may be causing the specific error you see since they would come out as:
D.NameFROM Driver A
Stop DWHERE A.
I've writen a servlet that builds an html page showing the content of a database. The code is:
Statement st = (Statement) conexion.createStatement();
ResultSet rs = st.executeQuery("select * from audiolist" );
while (rs.next())
{
contador++;
out.println("<tr>");
String k = rs.getString("Tittle");
String l = rs.getString("Autor");
String m = rs.getString("Album");
out.println("<td>"+"<input type=\"radio\" name=\"titulo<%="+contador+"%>\"value=\""+k+"\">");
out.println("<td>" + k + "</td>");
out.println("<td>" + l + "</td>");
out.println("<td>" + m + "</td>");
out.println("</tr>");
}
out.println("</table></center>");
out.println("<tr><td colspan=2><input type=submit></td></tr>");
out.println("</form>");
I've added a radio button to each row. With this code I get to show in the browser a table with the content of the database. When I click on submit I want send to another servlet the vale 'k' for the row selected. I'm having a hard time with this. I think I'm sending the value incorrectly. In the second servlet, is it enough to use getParameter() in order to get the info?
Thanks!
In the second servlet you can use:
String value = request.getParameter("tituloX");
to read the value. You need to know the name of the parameter to do. If this is not known, you can try to enumerate the parameters:
for ( Enumeration e = request.getParameterNames(); e.hasMoreElements();) {
String param = (String) e.nextElement();
String value = request.getParameter(param );
}
This only works for parameters with a single value.
Is this line correct?
out.println("<td>"+"<input type=\"radio\" name=\"titulo<%="+contador+"%>\"value=\""+k+"\">");