I would like to generate SQL statement from my Dictionary object. Because i have to eliminate the update process of empty string in corresponding column. i can do this via Swift code but doing this repeat action not good. is there any way to do this via SQL Statement?.
i have found some link on StackOverflow.
Asp.net link
and MySQL StackOverflow link
like sample example in python code
def insertFromDict(table, dict):
"""Take dictionary object dict and produce sql for
inserting it into the named table"""
sql = 'INSERT INTO ' + table
sql += ' ('
sql += ', '.join(dict)
sql += ') VALUES ('
sql += ', '.join(map(dictValuePad, dict))
sql += ');'
return sql
def dictValuePad(key):
return '%(' + str(key) + ')s'
let r = sqlFrom(dict: ["name" : "String", "type" : "sort"], for: "MyTable")
print(r)
Needed function:
func sqlFrom(dict : [String : String], for table : String) -> String {
let keys = dict.keys.joined(separator: ", ")
var values = dict.values.joined(separator: "', '")
values = """
'\(values)'
"""
let sql = "INSERT INTO \(table) ( \(keys) ) VALUES ( \( values) );"
return sql
}
Check result here:
Following method will do the job, but will not prevent you from sql injections
func insertStatement(table: String, dict: [String : Any]) -> String {
let values: [String] = dict.values.compactMap { value in
if value is String || value is Int || value is Double {
return "'\(value)'"
} else if let date = value as? Date {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd"
return "'" + dateFormatter.string(from: date) + "'"
}
// handle other types if necessary
return nil
}
return "INSERT INTO \(table) (" + dict.keys.joined(separator: ",") + ") VALUES (" + values.joined(separator: ",") + ")"
}
Usage:
insertStatement(table: "test_table", dict: ["id": 8, "name" : "John", "age" : Date()])
Output: INSERT INTO test_table(id,age,name) VALUES ('8','2019-04-24','John')
To prevent from SQL injections you have to use prepared statements to bind values, such as in the PHP's PDO library, like so:
func insertStatement(table: String, dict: [String : Any]) {
let columns = dict.keys.joined(separator: ",")
let values = dict.keys.map({ ":" + $0 }).joined(separator: ",")
// build the statement
let sql = "INSERT INTO " + table + "(" + columns + ") VALUES (" + values + ")"
var bind: [String : Any] = [:]
for (column, value) in dict {
bind[":\(column)"] = value
}
}
Related
Ok , I"m doing what looks like a simple Dapper query
but if I pass in my studId parameter, it blows up with this low level networking exception:
{"A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied."}
if I comment out the line of sql that uses it, fix the where clause, ,and comment out the line where it's added the the parameters object. It retrieves rows as expected.
I've spent the last 2.5 days trying everything I could think of, changing the names to match common naming patterns, changing type to a string (just gave a error converting string to number), yadda yadda yadda..
I'm at a complete loss as to why it doesn't like that parameter, I look at other code that works and they pass Id's just fine...
At this point I figure it has to be an ID-10-t that's staring me in the face and I'm just assuming my way right past it with out seeing it.
Any help is appreciated
public List<StudDistLearnSchedRawResponse> GetStudDistanceLearningScheduleRaw( StudDistLearnSchedQueryParam inputs )
{
var aseSqlConnectionString = Configuration.GetConnectionString( "SybaseDBDapper" );
string mainSql = " SELECT " +
" enrollment.stud_id, " +
" sched_start_dt, " +
" sched_end_dt, " +
" code.code_desc, " +
" student_schedule_dl.enrtype_id, " +
" student_schedule_dl.stud_sched_dl_id, " +
" dl_correspond_cd, " +
" course.course_name, " +
" stud_course_sched_dl.sched_hours, " +
" actual_hours, " +
" course_comments as staff_remarks, " + // note this column rename - EWB
" stud_course_sched_dl.sched_item_id , " +
" stud_course_sched_dl.stud_course_sched_dl_id " +
" from stud_course_sched_dl " +
" join student_schedule_dl on student_schedule_dl.stud_sched_dl_id = stud_course_sched_dl.stud_sched_dl_id " +
" join course on stud_course_sched_dl.sched_item_id = course.sched_item_id " +
" left join code on student_schedule_dl.dl_correspond_cd = code.code_id " +
" join enrollment_type on student_schedule_dl.enrtype_id = enrollment_type.enrtype_id " +
" join enrollment on enrollment_type.enr_id = enrollment.enr_id " +
" where enrollment.stud_id = #studId " +
" and sched_start_dt >= #startOfWeek" +
" and sched_end_dt <= #startOfNextWeek";
DapperTools.DapperCustomMapping<StudDistLearnSchedRawResponse>();
//string sql = query.ToString();
DateTime? startOfWeek = StartOfWeek( inputs.weekStartDateTime, DayOfWeek.Monday );
DateTime? startOfNextWeek = StartOfWeek( inputs.weekStartDateTime.Value.AddDays( 7 ) , DayOfWeek.Monday );
try
{
using ( IDbConnection db = new AseConnection( aseSqlConnectionString ) )
{
db.Open();
var arguments = new
{
studId = inputs.StudId, // it chokes and gives a low level networking error - EWB
startOfWeek = startOfWeek.Value.ToShortDateString(),
startOfNextWeek = startOfNextWeek.Value.ToShortDateString(),
};
List<StudDistLearnSchedRawResponse> list = new List<StudDistLearnSchedRawResponse>();
list = db.Query<StudDistLearnSchedRawResponse>( mainSql, arguments ).ToList();
return list;
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.ToString());
return null;
}
}
Here is the input object
public class StudDistLearnSchedQueryParam
{
public Int64 StudId;
public DateTime? weekStartDateTime;
}
Here is the dapper tools object which just abstracts some ugly code to look nicer.
namespace EricSandboxVue.Utilities
{
public interface IDapperTools
{
string ASEConnectionString { get; }
AseConnection _aseconnection { get; }
void ReportSqlError( ILogger DalLog, string sql, Exception errorFound );
void DapperCustomMapping< T >( );
}
public class DapperTools : IDapperTools
{
public readonly string _aseconnectionString;
public string ASEConnectionString => _aseconnectionString;
public AseConnection _aseconnection
{
get
{
return new AseConnection( _aseconnectionString );
}
}
public DapperTools( )
{
_aseconnectionString = Environment.GetEnvironmentVariable( "EIS_ASESQL_CONNECTIONSTRING" );
}
public void ReportSqlError( ILogger DalLog, string sql, Exception errorFound )
{
DalLog.LogError( "Error in Sql" );
DalLog.LogError( errorFound.Message );
//if (env.IsDevelopment())
//{
DalLog.LogError( sql );
//}
throw errorFound;
}
public void DapperCustomMapping< T >( )
{
// custom mapping
var map = new CustomPropertyTypeMap(
typeof( T ),
( type, columnName ) => type.GetProperties( ).FirstOrDefault( prop => GetDescriptionFromAttribute( prop ) == columnName )
);
SqlMapper.SetTypeMap( typeof( T ), map );
}
private string GetDescriptionFromAttribute( System.Reflection.MemberInfo member )
{
if ( member == null ) return null;
var attrib = (Dapper.ColumnAttribute) Attribute.GetCustomAttribute( member, typeof(Dapper.ColumnAttribute), false );
return attrib == null ? null : attrib.Name;
}
}
}
If I change the SQL string building to this(below), but leave everything else the same(Including StudId in the args struct)... it doesn't crash and retrieves rows, so it's clearly about the substitution of #studId...
// " where enrollment.stud_id = #studId " +
" where sched_start_dt >= #startOfWeek" +
" and sched_end_dt <= #startOfNextWeek";
You name your data members wrong. I had no idea starting a variable name with # was possible.
The problem is here:
var arguments = new
{
#studId = inputs.StudId, // it chokes and gives a low level networking error - EWB
#startOfWeek = startOfWeek.Value.ToShortDateString(),
#startOfNextWeek = startOfNextWeek.Value.ToShortDateString(),
};
It should have been:
var arguments = new
{
studId = inputs.StudId, // it chokes and gives a low level networking error - EWB
startOfWeek = startOfWeek.Value.ToShortDateString(),
startOfNextWeek = startOfNextWeek.Value.ToShortDateString(),
};
The # is just a hint to Dapper, that it should replace with a corresponding member name.
## has special meaning in some SQL dialects, that's probably what makes the trouble.
So here's what I Found out.
The Sybase implementation has a hard time with Arguments.
It especially has a hard time with arguments of type int64 (this existed way pre .NetCore)
So If you change the type of the passed in argument from int64 to int32, everything works fine.
You can cast it, or just change the type of the method parameter
Suppose I query a table which contains raw json in a column, or create json myself with a subquery like this:
select
p.name,
(select json_build_array(json_build_object('num', a.num, 'city', a.city)) from address a where a.id = p.addr) as addr
from person p;
How can I instruct Spring's NamedParameterJdbcTemplate not to escape
the addr column but leave it alone?
So far it insists returning me something like this:
[{
name: "John",
addr: {
type: "json",
value: "{"num" : "123", "city" : "Luxembourg"}"
}
}]
This is the working solution.
Service:
#Transactional(readOnly = true)
public String getRawJson() {
String sql = "select json_agg(row_to_json(json)) from ( "
+ "select "
+ "p.id, "
+ "p.name, "
+ "(select array_to_json(array_agg(row_to_json(c))) from ( "
+ " ... some subselect ... "
+ ") c ) as subq "
+ "from person p "
+ "where type = :type "
+ ") json";
MapSqlParameterSource params = new MapSqlParameterSource("type", 1);
return jdbcTemplate.queryForObject(sql, params, String.class);
}
Controller:
#ResponseBody
#GetMapping(value = "/json", produces = MediaType.APPLICATION_JSON_VALUE)
public String getRawJson() {
return miscService.getRawJson();
}
The key is the combination of json_agg and row_to_json / array_to_json plus returning a String to avoid any type conversions.
Using scala 2.11 and Slick 2.11
In a scala class, I have 2 methods:
getSQL which returns String SQL
getSqlStreamingAction which returns a composed SqlStreamingAction using sql interpolator
The code
def getSQL(id: Int): String = {
var fields_string = "";
for ((k,v) <- field_map) fields_string += k + ", ";
fields_string = fields_string.dropRight(2) // remove last ", "
"SELECT "+ fields_string +" FROM my_table WHERE id = " + id
}
def getSqlStreamingAction (id: Int): SqlStreamingAction[Vector[OtherObject], OtherObject, Effect] = {
val r = GetResult(r => OtherObject(r.<<, r.<<))
// this works
var fields_string = "";
for ((k,v) <- field_map) fields_string += k + ", ";
sql"""SELECT #$fields_string FROM my_table WHERE id = #$id""".as(r)
// But I want to use the method getSQL to retrieve the SQL String
// I imagine something like this, but of course it doesn't work :)
//sql"getSQL($id)".as(r)
I want to have separated methods for unit tests purposes, so I want to use getSQL method for sql interpolator
So, how can I use a method for Slick sql interpolator?
Note: I'm pretty new in Scala
-1 for me.
Solution:
def getSqlStreamingAction (id: Int): SqlStreamingAction[Vector[OtherObject], OtherObject, Effect] = {
val r = GetResult(r => OtherObject(r.<<, r.<<))
var sql_string: String = getSQL(id)
sql"""#$sql_string""".as(r)
Generic Fetch XML To Get All attributes from any entity in Microsoft Dynamics CRM 2011?
if you want it to be generic, youll have to use reflection to loop through the members and build the query xml dynamically.
something like:
Type type = TypeOf(Contact);
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
/////here you chain the members for the xml
Console.WriteLine("Name: " + property.Name + ", Value: " + property.GetValue(obj, null));
}
To fetch details from any entity use below method.
Please read Note and Parameter Description before using this generic Fetchxml generator.
Note : fieldToQuery, operatorForCondition, fieldQueryValue Should have Array Same count to work this function and well Mappep with respective to each other to get desired result
parameter name = "entityName" = Name of Entity of which details to fetch.
parameter name = "fieldsToSearch" = What all fields you want to fetch, if Sent Null, by default all fields are fetched from entity
parameter name = "filterType" = "AND" or "OR"
parameter name = "fieldToQuery" = Array of Field name on which to query
parameter name = "operatorForCondition" = Array of operator between fieldToQuery(Field Name) and fieldQueryValue(Field Value) like "eq, like"
parameter name = "fieldQueryValue" = Array of Field Value respective to fieldToQuery (Field Name) by which to query
Function stats from here
`
public static Microsoft.Xrm.Sdk.EntityCollection RetrieveEntityDetailsByFetchXml(string entityName, string[] fieldsToSearch, string filterType, string[] fieldToQuery, string[] operatorForCondition, string[] fieldQueryValue)
{
string _fetchDetailsXml = #"<fetch version='1.0' mapping='logical' output-format='xml-platform'> <entity name='" + entityName + "'> ";
_fetchDetailsXml = GenerateFetchXMLForAttributes(fieldsToSearch, _fetchDetailsXml);
_fetchDetailsXml += "<filter type='" + filterType + "'>";
if (fieldQueryValue.Count() != fieldToQuery.Count() && fieldToQuery.Count() != operatorForCondition.Count())
{
throw new ApplicationException("FieldtoQuery and FieldQueryValue are not mapped correctly fieldToQuery : " + fieldToQuery.Count() + " fieldQueryValue : " + fieldQueryValue.Count() + ".");
}
_fetchDetailsXml = GenerateFetchXMLForConditions(fieldToQuery, operatorForCondition, fieldQueryValue, _fetchDetailsXml);
_fetchDetailsXml += "</filter> </entity> </fetch>";
Microsoft.Xrm.Sdk.EntityCollection _entityDetailsColl = CrmConnectionsManager.OrganizationServiceProxy.RetrieveMultiple(new FetchExpression(_fetchDetailsXml));
// Note : "_entityDetailsColl" cast this object to respective Entity object
if (_entityDetailsColl != null && _entityDetailsColl.Entities.Count() > 0)
{
return _entityDetailsColl;
}
return null;
} `
`
public static string GenerateFetchXMLForAttributes(string[] fieldsToSearch, string fetchXml)
{
if (fieldsToSearch != null && fieldsToSearch.Count() > 0)
{
foreach (string field in fieldsToSearch)
{
fetchXml += "<attribute name='" + field + "' />";
}
}
else
{
fetchXml += "<all-attributes/>";
}
return fetchXml;
}
public static string GenerateFetchXMLForConditions(string[]fieldToQuery,string[] operatorForCondition, string[] fieldQueryValue, string _fetchDetailsXml)
{
if (fieldToQuery != null && fieldToQuery.Count() > 0)
{
for (int count = 0; count < fieldToQuery.Count(); count++)
{
_fetchDetailsXml += "<condition attribute='" + fieldToQuery[count] + "' operator='" + operatorForCondition[count] + "' value='" + fieldQueryValue[count] + "' uiname='' uitype='' /> ";
}
}
else
{
_fetchDetailsXml += "<all-attributes/>";
}
return _fetchDetailsXml;
}
`
Retrieving “all attributes” is computationally more expensive than retrieving just those you need (also consider the IO cost). If you are looking for a way to view the attributes then write code for just those you need try this:
In the CRM web GUI:
1.Navigate to the view that displays the records in question
2.Click the Advanced Find button in the Ribbon Bar
3.Configure your “find” until it shows the records you are looking for
4.Click the Download Fetch XML button in the Ribbon Bar
5.Open the file with a text viewer (or your favorite development tool)
If you want to use this XML directly you might consider:
Use FetchXML to Construct a Query
http://msdn.microsoft.com/en-us/library/gg328117.aspx
I am using sql prepared statements in my application.
The statements are prepared fine and executed fine.
After that ,when I see the table, there are no entries.
Code snippet:
void DirEntTable::do_init()
{
m_insertIntoSrvrEntTable.setStatement("INSERT INTO " + tableName() + " (entKey, srvrType, serverID, serverEntID) VALUES (" + entKeyField + ", " + srvrTypeField + ", " + serverIDField + ", " + serverEntIDField + ")");
m_insertIntoSrvrEntTable.setConnection(m_db);
if ((rc = m_insertIntoSrvrEntTable.prepare()) != SQLITE_OK)
{
LOGDEBUG("DirEntTable", "insertIntoSrvrEntTable prepare failed (%d) table %s\n", rc, tableName().c_str());
}
}
eErrorT DirEntTable::insertIntoSrvrEntTable(const int entryId, const int serverType,
const std::string &serverID, const std::string &serverEntID)
{
LOGDEBUG(__FUNCTION__, "\nvalues : entryId = %d, serverType = %d, serverID = %s, serverEntID =%s\n",entryId,serverType,serverID.c_str(),serverEntID.c_str());
eErrorT rc = kNoError;
m_insertIntoSrvrEntTable.bindInt(entKeyField, entryId);
m_insertIntoSrvrEntTable.bindInt(srvrTypeField, serverType);
m_insertIntoSrvrEntTable.bindText(serverIDField, serverID);
m_insertIntoSrvrEntTable.bindText(serverEntIDField, serverEntID);
if (!m_insertIntoSrvrEntTable())
{
rc = kFuncReturnedError;
}
m_insertIntoSrvrEntTable.reset();
return rc;
}
Output:
values : entryId = 46, serverType = 2, serverID = gds0, serverEntID =gds:330
query "INSERT INTO gdsEntries (entKey, srvrType, serverID, serverEntID) VALUES (:entKey, :srvrType, :serverID, :serverEntID)"
Please help me in understanding what could be wrong.