I have a DBML with a class that contains a timestamp column in sql.
The property in the DBML is declared as: (only relevant fields specified here)
Auto generated value:true
Name: timestamp
Nullable: false
Server data type: rowversion NOT NULL
Source: Timestamp
Time Stamp:true
Type: binary
Update check:never
In my logic, I insert into this table. However, I'm surprised to see that the generated sql looks something like this:
exec sp_executesql N'INSERT INTO [dbo].Foo( /* elided */)
VALUES (#p0, #p1, #p2, #p3, #p4, #p5, #p6, #p7, #p8, #p9, #p10, #p11, #p12, #p13, #p14, #p15, #p16, #p17, #p18, #p19, #p20, #p21, #p22, #p23, #p24, #p25)
SELECT [t0].[Timestamp]
FROM [dbo].[Foo] AS [t0]
WHERE [t0].[Id] = #p26', /* elided */
I'd like to get rid of that SELECT statement - I don't use the result.
Is that possible, or is it mandated that for object tracking the datacontext must know what the timestamp was of that new record?
I recognise that I could switch to using an SP for the insert method, but would prefer to avoid that.
The additional select is required to update the timestamp that the local instance of the object uses when updating itself in the concurrency check for any subsequent update/delete clauses. Since the RowVersion (TimeStamp) value is updated everytime the row is changed/inserted, the client needs the new version, otherwise a subsequent update would fail because the timestamp value would no longer be the same.
Related
I'm having some odd SQL problems when inserting new rows into a table. I have set some columns to NULL, as I have with another table in my database. Obviously when no data is passed through on insertion it should enter NULL into the record, however currently it is not.
I have checked all settings in comparison with my other table (which is inserting records as NULL correctly) but can't find the issue. The columns appear as below, in both tables.
`statement_1` varchar(255) DEFAULT NULL,
No data is being pasted through (so not a blank space issue). Can anyone suggest why one table is doing as expected but the other is not?
Using below as the insert statement
$statement_a = "INSERT INTO statements (ucsid, statement_1, statement_2, statement_3, statement_4, statement_5, statement_6, statement_7, statement_8, statement_9, statement_10) VALUES (:ucsid, :statement_1, :statement_2, :statement_3, :statement_4, :statement_5, :statement_6, :statement_7, :statement_8, :statement_9, :statement_10)";
$q_a = $this->db_connection->prepare($statement_a);
$q_a->execute(array(':ucsid'=>$ucsid,
':statement_1'=>$statement_1,
':statement_2'=>$statement_2,
':statement_3'=>$statement_3,
':statement_4'=>$statement_4,
':statement_5'=>$statement_5,
':statement_6'=>$statement_6,
':statement_7'=>$statement_7,
':statement_8'=>$statement_8,
':statement_9'=>$statement_9,
':statement_10'=>$statement_10));
I can not add comments as I am new:
Try a simple INSERT statement using NOT phpmyadmin. Try
http://www.heidisql.com/ OR https://www.mysql.com/products/workbench/
INSERT INTO statements (ucsid) VALUES (123)
INSERT INTO statements (ucsid, statement_1) VALUES (123, NULL)
In both cases the statement_1 should be NULL. Which in your case most likely is not. However that would tell the problem lies in the database table and NOT with php or the php execute method you are using.
Also is the statement_1 field defined as NOT NULL and the default set as NULL? which can not happen.
Try recreating a new database and a new table with no records and than try inserting NULL as values as a test.
Also can you post the SQL of your database and table with Character Set and Collation
I've fixed the issue by ensuring that NULL is passed through the functions if nothing has been inserted by using the following code
if($_POST['statement_1'] == '') { $statement_1 = NULL; } else { $statement_1 = $_POST['statement_1']; }
Here the value passed by the varriable $statement_1 will be ""
Try this query SELECT * FROM my_table WHERE statement_1 ="".You will get rows.
Which means you are assigning some values to $statement_1 else it should be null.
Check your code. Hope this helps
So i do a simple query like so:
connection.query("UPDATE workers SET timestamp='"+thedate+"' WHERE id = " + id,function(err,upres){
connection.release();
if(!err) {
console.log('updated record')
console.log(upres);
}
})
console.log reveals the data format as: 2015-04-02 19:29:14
And if i debug the SQL statement, that turns out to be:
UPDATE workers SET timestamp='2015-04-02 21:31:16' WHERE id = 3;
However, when i list the data, the output is:
[{"id":3,"worker":"John Doe","timestamp":"2015-04-01T22:00:00.000Z","duration":30}]
This is way off compared to the time that is being reported?
What is causing this?
You do not know how MySQL is turning your VARCHAR into a date. There are a lot of configuration options. It would be better to use the STR_TO_DATE function to circumvent all of the assumptions. Here is a link to the docs for STR_TO_DATE().
As a side note, I would strongly recommend using prepared statements as a way to safeguard your application against errors and sql injection.
EDITS:
In regards to your questions, the column could be DATETIME, but your value you are assigning is a VARCHAR
'UPDATE workers SET timestamp = ? WHERE id = ?', ['4/2/2015 3:00:00 PM', 3'], [callBackFunction]
Based on what you said about the conversion not working, I am suspicious about the data type for the timestamp column.
SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE NAME = 'workers'
A statement like that should give you all of the information about that column. You could also find this in a GUI, if you have access. There are three different date types in MySQL date, datetime, or timestamp. This is most likely a DATE column, that will not be able to hold the time.
We have a requirement of generating SSRS reports from where we need to convert multi-valued string and integer parameters to datatable and pass it to stored procedure. The stored procedure contains multiple table type parameters. Earlier we used varchar(8000) but it was also crossing the datatype limit. Then we thought to introducing datatable concept. But we were not aware of how to pass values from SSRS.
We found a solution from GruffCode on Using Table-Valued Parameters With SQL Server Reporting Services.
The solution solved my problem, and we're able to generate reports. However, sometimes SSRS returns the two following errors:
An error has occurred during report processing.
Query execution failed for dataset 'DSOutput'.
String or binary data would be truncated. The statement has been terminated.
And
An unexpected error occurred in Report Processing.
Exception of type 'System.OutOfMemoryException' was thrown.
I'm not sure when and where it's causing the issue.
The approach outlined in that blog post relies on building an enormous string in memory in order to load all of the selected parameter values into the table-valued parameter instance. If you are selecting a very large number of values to pass into the query I could see it potentially causing the 'System.OutOfMemoryException' while trying to build the string containing the insert statements that will load the parameter.
As for the 'string or binary data would be truncated' error that sounds like it's originating within the query or stored procedure that the report is using to gather its data. Without seeing what that t-sql looks like I couldn't say why that's happening, but I'd guess that it's also somehow related to selecting a very large number of parameter values.
Unfortunately I'm not sure that there's a workaround for this, other than trying to see if you could figure out a way to select fewer parameter values. Here's a couple of rough ideas:
If you have a situation where users might select a handful of parameter values or all parameter values then you could have the query simply take a very simple boolean value indicating that all values were selected rather than making the report send all of the values in through a parameter.
You could also consider "zooming out" of your parameter values a bit and grouping them together somehow if they lend themselves to that. That way users would be selecting from a smaller number of parameter values that represent a group of the individual values all rolled up.
I'm not a fan of using a Text parameter and EXEC in the SQL statement like the article you referenced describes as doing so is subject to SQL injection. The default SSRS behavior with a Multi-value parameter substitutes a comma-separated list of the values directly in place of the parameter when the query is sent to the SQL server. That works great for simple IN queries, but can be undesirable elsewhere. This behavior can be bypassed by setting the Parameter Value on the DataSet to an expression of =Join(Parameters!CustomerIDs.Value, ", "). Once you have done that you can get a table variable loaded by using the following SQL:
DECLARE #CustomerIDsTable TABLE (CustomerID int NOT NULL PRIMARY KEY)
INSERT INTO #CustomerIDsTable (CustomerID)
SELECT DISTINCT TextNodes.Node.value(N'.', N'int') AS CustomerID
FROM (
SELECT CONVERT(XML, N'<A>' + COALESCE(N'<e>' + REPLACE(#CustomerIDs, N',', N'</e><e>') + N'</e>', '') + N'</A>') AS pNode
) AS xmlDocs
CROSS APPLY pNode.nodes(N'/A/e') AS TextNodes(Node)
-- Do whatever with the resulting table variable, i.e.,
EXEC rpt_CustomerTransactionSummary #StartDate, #EndDate, #CustomerIDsTable
If using text instead of integers then a couple of lines get changed like so:
DECLARE #CustomerIDsTable TABLE (CustomerID nvarchar(MAX) NOT NULL PRIMARY KEY)
INSERT INTO #CustomerIDsTable (CustomerID)
SELECT DISTINCT TextNodes.Node.value(N'.', N'nvarchar(MAX)') AS CustomerID
FROM (
SELECT CONVERT(XML, N'<A>' + COALESCE(N'<e>' + REPLACE(#CustomerIDs, N',', N'</e><e>') + N'</e>', '') + N'</A>') AS pNode
) AS xmlDocs
CROSS APPLY pNode.nodes(N'/A/e') AS TextNodes(Node)
-- Do whatever with the resulting table variable, i.e.,
EXEC rpt_CustomerTransactionSummary #StartDate, #EndDate, #CustomerIDsTable
This approach also works well for handling user-entered strings of comma-separated items.
This query works fine in the query window of SQL Server 2005, but throws error when I run it in Execute SQL Task in the ssis package.
declare #VarExpiredDays int
Select #VarExpiredDays= Value1 From dbo.Configuration(nolock) where Type=11
DECLARE #VarENDDateTime datetime,#VarStartDateTime datetime
SET #VarStartDateTime= GETDATE()- #VarExpiredDays
SET #VarENDDateTime=GETDATE();
select #VarStartDateTime
select #VarENDDateTime
SELECT * FROM
(SELECT CONVERT(Varchar(11),#VarStartDateTime,106) AS VarStartDateTime) A,
(SELECT CONVERT(Varchar(11),#VarENDDateTime,106) AS VarENDDateTime) B
What is the issue here?
Your intention is to retrieve the values of start and end and assign those into SSIS variables.
As #Diego noted above, those two SELECTS are going to cause trouble. With the Execute SQL task, your resultset options are None, Single Row, Full resultset and XML. Discarding the XML option because I don't want to deal with it and None because we want rows back, our options are Single or Full. We could use Full, but then we'd need to return values of the same data type and then the processing gets much more complicated.
By process of elimination, that leads us to using a resultset of Single Row.
Query aka SQLStatement
I corrected the supplied query by simply removing the two aforementioned SELECTS. The final select can be simplified to the following (no need to put them into derived tables)
SELECT
CONVERT(Varchar(11),#VarStartDateTime,106) AS VarStartDateTime
, CONVERT(Varchar(11),#VarENDDateTime,106) AS VarENDDateTime
Full query used below
declare #VarExpiredDays int
-- I HARDCODED THIS
Select #VarExpiredDays= 10
DECLARE #VarENDDateTime datetime,#VarStartDateTime datetime
SET #VarStartDateTime= GETDATE()- #VarExpiredDays
SET #VarENDDateTime=GETDATE();
/*
select #VarStartDateTime
select #VarENDDateTime
*/
SELECT * FROM
(SELECT CONVERT(Varchar(11),#VarStartDateTime,106) AS VarStartDateTime) A,
(SELECT CONVERT(Varchar(11),#VarENDDateTime,106) AS VarENDDateTime) B
Verify the Execute SQL Task runs as expected. At this point, it simply becomes a matter of wiring up the outputs to SSIS variables. As you can see in the results window below, I created two package level variables StartDateText and EndDateText of type String with default values of an empty string. You can see in the Locals window they have values assigned that correspond to #VarExpiredDays = 10 in the supplied source query
Getting there is simply a matter of configuring the Result Set tab of the Execute SQL Task. The hardest part of this is ensuring you have a correct mapping between source system type and SSIS type. With an OLE DB connection, the Result Name has no bearing on what the column is called in the query. It is simply a matter of referencing columns by their ordinal position (0 based counting).
Final thought, I find it better to keep things in their base type, like a datetime data type and let the interface format it into a pretty, localized value.
you have more that one output type. You have two variables and one query.
You need to select only one on the "resultset" propertie
are you mapping these to the output parameters?
select #VarStartDateTime
select #VarENDDateTime
I have a LINQ to SQL class "VoucherRecord" based on a simple table. One property "Note" is a string that represents an nvarchar(255) column, which is non-nullable and has a default value of empty string ('').
If I instantiate a VoucherRecord the initial value of the Note property is null. If I add it using a DataContext's InsertOnSubmit method, I get a SQL error message:
Cannot insert the value NULL into column 'Note', table 'foo.bar.tblVoucher'; column does not allow nulls. INSERT fails.
Why isn't the database default kicking in? What sort of query could bypass the default anyway? How do I view the generated sql for this action?
Thanks for your help!
If you omit the column, the value becomes the database default, but anything you insert is used instead of the default, example:
INSERT INTO MyTable (ID, VoucherRecord) Values(34, NULL) -- Null is used
INSERT INTO MyTable (ID) Values(34) -- Default is used
Picture for example you have a column that defaults to anything but NULL, but you specifically want NULL...for that to ever work, whatever value you specify MUST override the default, even in the case of NULL.
You need to set Auto-Sync to OnInsert, Auto Generated Value to true and Nullable to false for your column to work. See here for a full run-down with explanation on the Linq side.
For viewing the generated SQL, I have to recommend LinqPad