I am trying to populate a table variable in SSRS and call a SP subsequently to process the data in it:
DECLARE #Tbl1 TABLE
(
D01 float,
D02 float,
D03 float,
D04 float,
D05 float,
...
D96 float
)
To populate it I use a text parameter #LS. The input is comma delimited string with 96 elements:
0.635316969,0.756943899,0.890520142,1.028008362,1.166350106,1.30511861,1.444527254,1.580948571,1.578743639,1.575542931,1.573195746,1.571346448,1.571275321,1.56992391,1.568003484,1.567221089,1.556836567,1.543820351,1.53037, ...., ,0.514543561
In a dataset I tried to populate the table first (after table variable declaration):
insert into #Tbl1
VALUES (#LS)
But got this error at run-time: "Column name or number of supplied values does not match table definition."
I tried JOIN(SPLIT()) with comma without luck. Any ideas?
Thanks!
The problem is the the #LS parameter is a single-value text parameter so you can't use it like that - you'd need to use a multi-value parameter.
So let's try something different. You don't need to create a temporary table because you could build your column values to give a dataset that you want using Sql like this:
SELECT 0.635316969 AS D01, 0.756943899 AS D02, ... , 0.514543561 AS D96
Fortunately almost everything in SSRS is an expression, so we just need to build this Sql statement dynamically from the #LS parameter using an expression. Go to the Report menu then Report Properties... and click the Code tab. Enter the following code:
Function MakeSql(LS As String) As String
Dim Sql As String
Dim Values() As String
Dim i As Integer
Sql = "SELECT "
Values = Split(LS, ",")
For i = 0 To Values.Length - 1
Sql = Sql + Values(i) + " AS D" + Right("0" + CStr(i+1), 2) + ", "
Next i
Sql = Left(Sql, Len(Sql) - 2) ' Remove trailing comma
Return Sql
End Function
So what we are doing is splitting the string into an array of values which we loop through to create a Sql statement that aliases these values to the field names we want.
Right-click your dataset, choose Dataset Properties and press the fx button beside the query textbox. This allows us to enter a text expression for our Sql statement rather than an actual Sql statement. Here we need to call the custom code function we created above which will insert our custom built Sql expression:
=Code.MakeSql(Parameters!LS.Value)
Make sure your dataset has the fields D01 to D96 (you'll have to set these up manually because SSRS can't analyse the Sql expression to determine the field values) and you're done!
Related
I am looking to use a string that takes in some parameters from my cells and use it as my sql statement like so:
" select * from table where " & data_from_cells & " group by ...;"
store it as sqlstring
let
mystring = sqlstring,
myQuery = Odbc.Query("driver={Oracle in etc etc etc", mystring)
and I run into this error
Formula.Firewall: Query '...' (step 'myQuery') references other queries or steps, so it may not directly access a data source. Please rebuild this data combination.
now apparently I can't combine external queries and another query -- but I am only using passed-on parameters from Excel for my sql string? I am hoping to use WITH keyword as well to make nested queries using parameters but it doesn't even let me combine values from excel with an sql statement..
to be clear, the data_from_cells was transformed and formatted as a string.
When queries that do stuff are called by other queries that do other stuff, sometimes you can get firewall issues.
The way to get around that is for everything to be done in a single query.
The way to get around that without ending up with horrible code is to change your called queries from returning the result to functions that return the result.
For sqlstring:
() => " select * from table where " & data_from_cells & " group by ...;" // returns a function that gets the query string when called
Then your "myQuery" query can be
let
mystring = sqlstring(), //note the parentheses!
myQuery = Odbc.Query("driver={Oracle in etc etc etc", mystring)
I want to compare two textboxes with data in a datatable and use this comparison operation to filter the datetable.
For example: I want to show all data (rows and columns) that have value x in which:
textbox1.text>x>textbox1.text
I have used "Like" operator inside string format to get the value that matches the value in the text-box completely but I could not do the required range filtering operation
Here is my code related to the specified question:
dv.RowFilter = string.Format("Type Like '%{0}%' and Gain Like" +
"'%{1}%'" +
"and Year Like'%{2}%' and MotorPower Like '%{3}%'" +
"and Profit Like '%{4}%'", textBoxType .Text,textBoxGain.Text
, textBoxYear.Text, textBoxBiggerthan.Text, textBoxKar.Text);
dataGridView1.DataSource = dv;
I have another input textbox called textBoxSmallerthan.Text
and I want to make my range for MotorPower column in datatable (datagridview) between textBoxBiggerthan.Text and textBoxSmallerthan.Text
The documentation here shows the numbers do not need be wrapped with single quote makers. So the format is:
Columnname < Number
So the final filter should be something like this:
dv.RowFilter = string.Format("Type Like '%{0}%' and Gain Like" +
"'%{1}%'" +
"and Year Like'%{2}%' and MotorPower > {3} and MotorPower < {4}" +
"and Profit Like '%{4}%'", textBoxType .Text,textBoxGain.Text
, textBoxYear.Text, textBoxSmallerthan.Text, textBoxBiggerthan.Text, textBoxKar.Text);
dataGridView1.DataSource = dv;
I have a CSV file with some integer column, now it 's saved as "" (empty string).
I want to COPY them to a table as NULL value.
With JAVA code, I have try these:
String sql = "COPY " + tableName + " FROM STDIN (FORMAT csv,DELIMITER ',', HEADER true)";
String sql = "COPY " + tableName + " FROM STDIN (FORMAT csv,DELIMITER ',', NULL '' HEADER true)";
I get: PSQLException: ERROR: invalid input syntax for type numeric: ""
String sql = "COPY " + tableName + " FROM STDIN (FORMAT csv,DELIMITER ',', NULL '\"\"' HEADER true)";
I get: PSQLException: ERROR: CSV quote character must not appear in the NULL specification
Any one has done this before ?
I assume you are aware that numeric data types have no concept of "empty string" ('') . It's either a number or NULL (or 'NaN' for numeric - but not for integer et al.)
Looks like you exported from a string data type like text and had some actual empty string in there - which are now represented as "" - " being the default QUOTE character in CSV format.
NULL would be represented by nothing, not even quotes. The manual:
NULL
Specifies the string that represents a null value. The default is \N
(backslash-N) in text format, and an unquoted empty string in CSV format.
You cannot define "" to generally represent NULL since that already represents an empty string. Would be ambiguous.
To fix, I see two options:
Edit the CSV file / stream before feeding to COPY and replace "" with nothing. Might be tricky if you have actual empty string in there as well - or "" escaping literal " inside strings.
(What I would do.) Import to an auxiliary temporary table with identical structure except for the integer column converted to text. Then INSERT (or UPSERT?) to the target table from there, converting the integer value properly on the fly:
-- empty temp table with identical structure
CREATE TEMP TABLE tbl_tmp AS TABLE tbl LIMIT 0;
-- ... except for the int / text column
ALTER TABLE tbl_tmp ALTER col_int TYPE text;
COPY tbl_tmp ...;
INSERT INTO tbl -- identical number and names of columns guaranteed
SELECT col1, col2, NULLIF(col_int, '')::int -- list all columns in order here
FROM tbl_tmp;
Temporary tables are dropped at the end of the session automatically. If you run this multiple times in the same session, either just truncate the existing temp table or drop it after each transaction.
Related:
How to update selected rows with values from a CSV file in Postgres?
Rails Migrations: tried to change the type of column from string to integer
postgresql thread safety for temporary tables
Since Postgres 9.4 you now have the ability to use FORCE_NULL. This causes the empty string to be converted into a NULL. Very handy, especially with CSV files (actually this is only allowed when using CSV format).
The syntax is as follow:
COPY table FROM '/path/to/file.csv'
WITH (FORMAT CSV, DELIMITER ';', FORCE_NULL (columnname));
Further details are explained in the documentation: https://www.postgresql.org/docs/current/sql-copy.html
If we want to replace all blank and empty rows with null then you just have to add emptyasnull blanksasnull in copy command
syntax :
copy Table_name (columns_list)
from 's3://{bucket}/{s3_bucket_directory_name + manifest_filename}'
iam_role '{REDSHIFT_COPY_COMMAND_ROLE}' emptyasnull blanksasnull
manifest DELIMITER ',' IGNOREHEADER 1 compupdate off csv gzip;
Note: It will apply for all the records which contains empty/blank values
I need to import certain information from an Excel file into an Access DB and in order to do this, I am using DAO.
The user gets the excel source file from a system, he does not need to directly interact with it. This source file has 10 columns and I would need to retrieve only certain records from it.
I am using this to retrieve all the records:
Set destinationFile = CurrentDb
Set dbtmp = OpenDatabase(sourceFile, False, True, "Excel 8.0;")
DoEvents
Set rs = dbtmp.OpenRecordset("SELECT * FROM [EEX_Avail_Cap_ALL_DEU_D1_S_Y1$A1:J65536]")
My problem comes when I want to retrieve only certain records using a WHERE clause. The name of the field where I want to apply the clause is 'Date (UCT)' (remember that the user gets this source file from another system) and I can not get the WHERE clause to work on it. If I apply the WHERE clause on another field, whose name does not have ( ) or spaces, then it works. Example:
Set rs = dbtmp.OpenRecordset("SELECT * FROM [EEX_Avail_Cap_ALL_DEU_D1_S_Y1$A1:J65536] WHERE Other = 12925")
The previous instruction will retrieve only the number of records where the field Other has the value 12925.
Could anyone please tell me how can I achieve the same result but with a field name that has spaces and parenthesis i.e. 'Date (UCT)' ?
Thank you very much.
Octavio
Try enclosing the field name in square brackets:
SELECT * FROM [EEX_Avail_Cap_ALL_DEU_D1_S_Y1$A1:J65536] WHERE [Date (UCT)] = 12925
or if it's a date we are looking for:
SELECT * FROM [EEX_Avail_Cap_ALL_DEU_D1_S_Y1$A1:J65536] WHERE [Date (UCT)] = #02/14/13#;
To use date literal you must enclose it in # characters and write the date in MM/DD/YY format regardless of any regional settings on your machine
I am rolling up a huge table by counts into a new table, where I want to change all the empty strings to NULL, and typecast some columns as well. I read through some of the posts and I could not find a query, which would let me do it across all the columns in a single query, without using multiple statements.
Let me know if it is possible for me to iterate across all columns and replace cells with empty strings with null.
Ref: How to convert empty spaces into null values, using SQL Server?
To my knowledge there is no built-in function to replace empty strings across all columns of a table. You can write a plpgsql function to take care of that.
The following function replaces empty strings in all basic character-type columns of a given table with NULL. You can then cast to integer if the remaining strings are valid number literals.
CREATE OR REPLACE FUNCTION f_empty_text_to_null(_tbl regclass, OUT updated_rows int)
LANGUAGE plpgsql AS
$func$
DECLARE
_typ CONSTANT regtype[] := '{text, bpchar, varchar}'; -- ARRAY of all basic character types
_sql text;
BEGIN
SELECT INTO _sql -- build SQL command
'UPDATE ' || _tbl
|| E'\nSET ' || string_agg(format('%1$s = NULLIF(%1$s, '''')', col), E'\n ,')
|| E'\nWHERE ' || string_agg(col || ' = ''''', ' OR ')
FROM (
SELECT quote_ident(attname) AS col
FROM pg_attribute
WHERE attrelid = _tbl -- valid, visible, legal table name
AND attnum >= 1 -- exclude tableoid & friends
AND NOT attisdropped -- exclude dropped columns
AND NOT attnotnull -- exclude columns defined NOT NULL!
AND atttypid = ANY(_typ) -- only character types
ORDER BY attnum
) sub;
-- RAISE NOTICE '%', _sql; -- test?
-- Execute
IF _sql IS NULL THEN
updated_rows := 0; -- nothing to update
ELSE
EXECUTE _sql;
GET DIAGNOSTICS updated_rows = ROW_COUNT; -- Report number of affected rows
END IF;
END
$func$;
Call:
SELECT f_empty2null('mytable');
SELECT f_empty2null('myschema.mytable');
To also get the column name updated_rows:
SELECT * FROM f_empty2null('mytable');
db<>fiddle here
Old sqlfiddle
Major points
Table name has to be valid and visible and the calling user must have all necessary privileges. If any of these conditions are not met, the function will do nothing - i.e. nothing can be destroyed, either. I cast to the object identifier type regclass to make sure of it.
The table name can be supplied as is ('mytable'), then the search_path decides. Or schema-qualified to pick a certain schema ('myschema.mytable').
Query the system catalog to get all (character-type) columns of the table. The provided function uses these basic character types: text, bpchar, varchar, "char". Only relevant columns are processed.
Use quote_ident() or format() to sanitize column names and safeguard against SQLi.
The updated version uses the basic SQL aggregate function string_agg() to build the command string without looping, which is simpler and faster. And more elegant. :)
Has to use dynamic SQL with EXECUTE.
The updated version excludes columns defined NOT NULL and only updates each row once in a single statement, which is much faster for tables with multiple character-type columns.
Should work with any modern version of PostgreSQL. Tested with Postgres 9.1, 9.3, 9.5 and 13.