SimpleJDBCCall handle out paramater with resultset - mysql

I am using spring jdbc. I want result set with out param. separately i done but together i am not able to do.
CREATE DEFINER=`xxx`#`%` PROCEDURE `client_xxxx`(
IN p_xxxx TINYINT(1) UNSIGNED,
IN p_result SMALLINT(2) UNSIGNED,
OUT p_result BIT ) BEGIN
IF EXISTS(SELECT 1 FROM xxx WHERE xxx = 1 AND xxx = 1) THEN
SELECT ...;
SET p_result = 0;
ELSE
SELECT ...;
SET p_result = 1;
END IF;
END
spring jdbc code
SimpleJdbcCall jdbcCall = new SimpleJdbcCall(dataSource).withProcedureName(sp);
List<Map<String, Object>> list = (List<Map<String, Object>>) jdbcCall.execute(paramsArray).get("#result-set-1");
list get the result set with result set how can i get p_result with that.

I find it in simple way that i miss.
public Map<String, Object> xxx(String sp, Object... paramsArray) {
SimpleJdbcCall jdbcCall = new SimpleJdbcCall(dataSource).withProcedureName(sp);
return jdbcCall.execute(paramsArray);
}
execute() gives two parameters default
i.e.
1) #result-set-1
2) #update-count-1
#result-set-1 result set i.e. select record
and #update-count-1 returns update count. If we want to access result with select statement with out parameter. we just have to declare out parameter. execute() gives all the things in Map<String, Object> type.
So from map we can get all the multiple values that stored procedure returns.
For example my SP like
PROCEDURE xxx(
IN xxxxTINYINT(1) UNSIGNED,
IN xxxSMALLINT(2) UNSIGNED,
OUT p_isconfig BIT
)
BEGIN
SELECT....
SET p_isconfig = 1;
END
So in #result-set-1 i get select result.
and p_isconfig gives me result to. If you have any confusion then you can iterate map and identify that how get return parameters.
Iterator i = map.keySet().iterator();
while ( i.hasNext() ) {
String key = (String) i.next();
String value = params.get( key );
System.out.println("key: " + key + " --- value: " + value) ;
}
This way i found solution after reading many things. If any one have other option for this solution then please share with me.

You can try morejdbc (available in maven central) to call your procedure, it's more laconic and it's type safe:
import static org.morejdbc.SqlTypes.BIGINT;
import static org.morejdbc.NamedJdbcCall.call;
import org.morejdbc.*;
...
private JdbcTemplate jdbcTemplate;
...
Out<Integer> out = Out.of(INTEGER);
jdbcTemplate.execute(call("client_xxxx")
.in("p_xxxx", pValue)
.out("p_result", out));
System.out.println("Result is " + out.get());
For ref_cursor out parameter and Oracle database you can use
Out<List<Record>> out = Out.of(OracleSqlTypes.cursor((rs, idx) -> new Record(rs)));
jdbcTemplate.execute(call("client_xxxx")
.in("p_xxxx", pValue)
.out("p_result", out)); // will auto-close ref-cursor
System.out.println("Got result records: " + out.get());

Related

Dataset has no values even though procedure is returning proper value

I have a procedure where I am using OPENJSON to display the Json string as key value pairs. When I execute the procedure, it is returning the expected value bu in controller, the dataset is empty. It only shows the table headers - key, value, type. No data at all. When I use a different very similar procedure, it it seems to work fine. Not sure what is happening. Please help!
Thanks in advance!
This is my procedure:
CREATE PROCEDURE [dbo].[PROC_NH_Journal_Tab1Data]
#EnterpriseId nvarchar,
#exactgroup nvarchar
AS
declare #json nvarchar(max)
set #json=(select Tab2Json from tbl_NH_T_JournalDataPost where
EnterpriseId=#EnterpriseId and GroupName = #exactgroup)
SELECT * FROM
OPENJSON ( #json )
Return 0
And here is my action:
public JsonResult GetAnswersFortab1(string exact)
{
string JSONresult = string.Empty;
string EnterpriseId = "User";
try
{
SqlConnection sqlcon = new SqlConnection(con);
SqlCommand cmd = new SqlCommand("[PROC_NH_Journal_Tab1Data]", sqlcon);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#EnterpriseId", EnterpriseId);
cmd.Parameters.AddWithValue("#exactgroup", exact);
sqlcon.Open();
SqlDataAdapter adapter = new SqlDataAdapter();
adapter.SelectCommand = cmd;
DataSet data;
data = new DataSet();
adapter.Fill(data, "Table2");
DataTable dt1 = data.Tables[0];
ViewBag.getJson = dt1;
}
The procedure when executed, gives a table with key, value pairs. But when I debug,in action, the 'data' is an empty table in 'DataSetVisualizer'. Empty table only with headers(key,value,type).No data is present.
Here is my Print #json from the procedure
key value type
emoji2 2 1
check2 on 1
check5 on 1
check7 on 1
hiddentext weds 1

MVC with no Entity Framework

From the below source tutorials:
https://www.youtube.com/watch?v=Jt9vSY802mM
http://www.dotnetawesome.com/2017/07/curd-operation-on-fullcalendar-in-aspnet-mvc.html
How do I do the above code samples without Entity Framework, by just using SQL queries?
For example in the above source code, instead of
var v = dc.Events.Where(a => a.EventID == eventID).FirstOrDefault();
if (v != null)
{
dc.Events.Remove(v);
dc.SaveChanges();
status = true;
}
I want to do
DELETE FROM Even WHERE EventID = {0}
FirstOrDefault() in LINQ is equivalent to LIMIT 1 in MySQL, hence the LINQ function can be converted to SQL commands using IF or CASE WHEN like this (assumed commands are running inside a stored procedure):
DELIMITER //
-- 'Events' is a DbSet name by common convention,
-- therefore table name should be 'Event'
CREATE PROCEDURE procedure_name (IN eventID INT)
BEGIN
DECLARE v INT;
SET v = SELECT EventID FROM Event WHERE EventID = eventID LIMIT 1;
CASE WHEN v IS NOT NULL
THEN DELETE FROM Event WHERE EventID = v
ELSE -- do something else
END
-- alternative:
-- IF(v IS NOT NULL, DELETE FROM Event WHERE eventID = v, 0)
-- other stuff here
END//
DELIMITER ;
Note: If EventID is a primary key column, you can remove LIMIT 1 because query result only return single value.
Then, use CALL procedure_name(eventID) or include procedure_name in MySqlCommand to execute it.
Couple of ways:
using raw query in Entity Framework:
Open connection string via SqlConnection and execute:
Pseudo code for method 1:
string sqlDeleteStatement = "DELETE FROM Even WHERE EventID = #id";
List<SqlParameter> parameterList = new List<SqlParameter>();
parameterList.Add(new SqlParameter("#id", 1)); delete id = 1
_context.Database.SqlQuery(sqlDeleteStatement, parameterList);
Pseudo code for method 2:
using(SqlConnection conn = new SqlConnection())
{
conn.ConnectionString = "Server=[server_name];Database=[database_name];Trusted_Connection=true";
string sqlDeleteStatement = "DELETE FROM Even WHERE EventID = #id";
SqlCommand command = new SqlCommand(sqlDeleteStatement , conn);
command.Parameters.Add(new SqlParameter("#id", 1)); //delete id = 1
command.ExecuteNonQuery();
}

Postgresql function plpython select json value

I'm using postgresql 9.6.
I build a function where i do a "selec"t like :
id = TD["new"]["id"]
qry = plpy.prepare ("SELECT (decode->>'key')::integer AS key FROM table where id = $1;", ["int"])
res= plpy.execute(qry,[id])
The request work fine, but the result hold key and value, not only value.
In fact, the result is like that : {"key":2937}
I want just the value.
The result object emulates a list or dictionary object. The result object can be accessed by row number and column name.
create or replace function pf()
returns integer as $$
query = 'select 1 as key'
rs = plpy.execute(query)
plpy.notice(rs.__str__())
return rs[0]['key']
$$ language plpythonu;
select pf();
NOTICE: <PLyResult status=5 nrows=1 rows=[{'key': 1}]>
pf
----
1
https://www.postgresql.org/docs/current/static/plpython-database.html

How to get a value from func/sp to a case statement using dynamic SQL?

hoping someone might be able to help me with a bit of an issue. Essentially i'm trying to get a rough size of all of the fields in my database as i'd like to do some math on it to guesstimate what the size will be with a compression technique applied to it.
I can do this for most fields by looking at the datatype and using the number of rows to get the number of bytes it's taking up. However on something like a varchar(max) field this is not as easy and so i decided to approach this by getting the average length within the column and multiplying by number of rows. But i've hit a snag which i'll describe below.
I have the following stored proc (i tried a function too but you can't call dynamic SQL from a function).
CREATE PROCEDURE dbo.getFieldSize(#column varchar(255), #table varchar(255), #ret decimal(15,7) OUTPUT)
AS
BEGIN
DECLARE #lengthSQL varchar(50)
/SET #lengthSQL = 'SELECT #ret = AVG(DATALENGTH(' + #column + ')) FROM [' + #table +']'/
SET #lengthSQL = 'SELECT #ret = AVG(DATALENGTH(' + #column + ')) FROM ' + #table
exec sp_executesql #lengthSQL
RETURN #ret
END
GO
And then i call it using...
SELECT b.TABLE_SCHEMA as 'Schema',
CASE WHEN DATA_TYPE IN ('nvarchar') AND CHARACTER_MAXIMUM_LENGTH <> -1 AND c.distinctItems <> 0 AND c.totalCount <> 0 THEN exec('select max(len(' + b.TABLE_CATALOG + ' + '.' + ' + b.COLUMN_NAME + '))')
FROM ....
The above is basically just checking to make sure it is a varchar(max) field and contains some values within the column. I then try and execute the SP and pass the column name and table name for which i need the avg length but i get the following error.
Msg 156, Level 15, State 1, Line 57
Incorrect syntax near the keyword 'exec'.
I learned you cannot call a dynamic SQL from a function and you cannot call a SP from a CASE statement. So at this point it seems like it's a catch 22 and i cannot do what i need using SQL. Can anyone think of any workarounds or i'm I out of luck on this?
Actually, you can do Dynamic SQL in a scalar UDF, it just needs to be a SQLCLR UDF ;-). But this is fairly simple to do using the in-process / internal connection (i.e. SqlConnection("Context Connection = true;");). Meaning, the assembly can be set to SAFE.
Also, object / column / index names are all NVARCHAR. And objects (if not also the others) are declared as sysname which is an alias for NVARCHAR(128). Just FYI.
So, something like the following (which I have tested and it does work):
[Microsoft.SqlServer.Server.SqlFunction(Name = "GetAvgBytes",
IsDeterministic = false, IsPrecise = true, DataAccess = DataAccessKind.Read)]
public static SqlInt32 GetAvgBytes([SqlFacet(MaxSize = 128)] SqlString TableName,
[SqlFacet(MaxSize = 128)] SqlString ColumnName)
{
int _AvgBytes = -1;
SqlConnection _Connection = new SqlConnection("Context Connection = true;");
SqlCommand _Command = _Connection.CreateCommand();
_Command.CommandType = CommandType.Text;
_Command.CommandText = "SELECT #AvgBytes = AVG(DATALENGTH(" + ColumnName.Value
+ ")) FROM " + TableName.Value + " WITH (NOLOCK);";
SqlParameter _Param = new SqlParameter("#AvgBytes", DbType.Int32);
_Param.Direction = ParameterDirection.Output;
_Command.Parameters.Add(_Param);
try
{
_Connection.Open();
_Command.ExecuteNonQuery();
_AvgBytes = (int)_Param.Value;
}
finally
{
_Connection.Close();
}
return _AvgBytes;
}

Grails is throwing a cannot be null error on a field without that limitation

Using GRAILs and MySQL to build my application.
I have a MySQL BEFORE INSERT trigger that works very well:
USE `scheduler`;
DELIMITER $$
CREATE DEFINER=`root`#`localhost` TRIGGER `devices_BINS` BEFORE INSERT ON `devices` FOR EACH ROW
begin
If new.device_type = 'DU' THEN
Select IFNULL(max(external_id), '00-000') into #oldMc from `devices` where device_type = 'DU';
SET #IntMc = CAST(Concat(left(#oldMc,2), right(#oldMc,3)) as unsigned);
SET #IntMc=#IntMc+1;
set #newMC = LPAD(CAST(#IntMc as CHAR(10)), 5, 0);
set new.external_id = CONCAT(left(#newMC, 2),'-',right(#newMC, 3));
elseiF new.device_type = 'ATM' THEN
set new.external_id = new.serial_number;
END IF;
end
When I implement the structure in a GRAILS domain, and try to create an entry i get:
Property [external_id] of class [class cms.Devices] cannot be null
from the objects Errors property.
Here is the odd thing: external_id is allowed to be null in the DB (even has Null as a default value); and the only constraint in the domain is external_id(blank:true). BTW: changing this seems to have no effect.
Any thoughts why? or how I can maybe just "Skip" the error in validation check of the controller?
here is the domain class
class Devices {
String external_id
String serial_number
String model_type
Device_Type device_type
Status status
String toString(){
"$device_type - $external_id"
}
enum Status {
Tentative, Active, Offline, Terminated
}
enum Device_Type {
DU, ATM
}
Locations locations
static constraints = {
device_type()
model_type()
serial_number(unique: true)
status()
external_id(blank:true)
}
static mapping = {
version false
id column: 'device_id'
locations column:'location_id'
}
}