I have a table in my database called notifications, data will be inserted into this table whenever notifications arrive from other users in my application. The table's schema looks like this:
CREATE TABLE [dbo].[notifications](
[id] [int] IDENTITY(1,1) NOT NULL,
[sender] [char](17) NULL,
[reciever] [char](17) NULL,
[letter_code] [char](15) NULL,
[txt] [nvarchar](max) NULL,
[dateandtime] [datetime2](7) NULL,
[letter_kind] [nvarchar](50) NULL,
[seen] [bit] NULL,
CONSTRAINT [PK_notifications] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
the inserted row must be something like this:
id || sender || reciever || letter_code || txt || dateandtime || letter_kind || seen
============================================================================================================
1 || 2 || 2 || 1734 || message || 2015-10-12 09:59:01 || PS || flase
today I was checking my database's tables, and I noticed something strange has happened. Some strange data are inserted into the notification table:
As you can see the txt column contains a very strange value:
1<div style="display:none">looking to cheat go how many men have affairs</div>
And other columns contain 1 !
Any idea?
PS: I'm sure in only one place data for this table will be written:
context.InsTotNotification(WebContext.Current.User.UserCode, CheckedUsersForSend.ElementAt(j), LetCods.ElementAt(i),
string.Format("letter kind {0} letter code {1} datetime.",
LetterKind, Convert.ToString(Convert.ToDouble(LetCods.ElementAt(i).Substring(4, 11)), CultureInfo.InvariantCulture)), DateTime.Now, LetterKind);
Update: There's no form for allowing users to input the data, data will be written using the backend not users.
Update 2: I'm using EntityFramework Database First and InsTotNotification is a stored procedure inside my context:
[Invoke]
public string InsTotNotification(string sender, string reciever,string letter_code,string Txt,DateTime dateandtime,string Letter_kind)
{
var MQuery = ObjectContext.InsTo_Notification(sender, reciever, letter_code, Txt, dateandtime, Letter_kind).FirstOrDefault();
return "Ok";
}
And here's the sp:
SET ANSI_NULLS OFF
GO
SET QUOTED_IDENTIFIER OFF
GO
ALTER PROCEDURE [dbo].[InsTo_Notification]
#Sender char(17),
#Reciever char(17),
#Letter_code char(15),
#Txt nvarchar(MAX),
#DateandTime datetime2,
#Letter_kind nvarchar(50)
AS
BEGIN TRANSACTION InsertNotifications
Declare #T1 int
INSERT notifications (sender, reciever, letter_code, txt, dateandtime, letter_kind)
values (#Sender, #Reciever, #Letter_code, #Txt, #DateandTime,#Letter_kind)
SELECT #T1=##ERROR
--------------------------
if (#T1=0)
BEGIN
COMMIT TRANSACTION InsertNotifications
SELECT #Letter_code as LetterNo
END
ELSE
BEGIN
ROLLBACK TRANSACTION InsertNotifications
SELECT 'NO' as 'It has Problem'
END
Update 3: There's also these types of rows in the table:
Notice that the text نامه PS به شماره 11968 به شما ارجاع داده شد in the selected row is the actual value for txt field.
definitely SQL Injection...
Is this coming from a Web application or something that can be reahed by the web, right?
Your stored procedure takes any char inputs without proper validation.
Try to check if parameters contain "<", ">", reserved SQL Server terms/statements or other unwanted chars.
Related
I'm customizing a legacy ASP.NET MVC application that uses both raw SQL and models. I have some data to be committed that has two decimal places for example 4,615.38, 11.51. When I attempt to commit data im getting an error
Error converting datatype varchar to numeric
I need help on how to properly define my table and stored procedure. Should I use any casting in table definition or LEFT function?
In TaxTableController.cs i have :
Models.TaxTable.Zimra zimra = new Models.TaxTable.Zimra();
zimra.TableName = Helpers.SanitiseInput(Convert.ToString(formcollection["TableName"]));
zimra.TierName = Helpers.SanitiseInput(Convert.ToString(formcollection["TierName"]));
zimra.MinSalary = Convert.ToDouble(formcollection["MinSalary"]);
zimra.MaxSalary = Convert.ToDouble(formcollection["MaxSalary"]);
zimra.CreatedOn = DateTime.Now;
zimra.CreatedBy = Convert.ToString(Session["UserId"]);
if (ModelState.IsValid)
{
using (SqlConnection conn = new SqlConnection(Helpers.DatabaseConnect))
{
SqlCommand cmd = new SqlCommand("SaveZimraTable", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#TableName", zimra.TableName);
cmd.Parameters.AddWithValue("#TierName", zimra.TierName);
cmd.Parameters.AddWithValue("#MaxSalary", zimra.MaxSalary);
cmd.Parameters.AddWithValue("#MinSalary", zimra.MinSalary);
cmd.Parameters.AddWithValue("#CreatedBy", zimra.CreatedBy);
cmd.Parameters.AddWithValue("#CreatedOn", zimra.CreatedOn);
My table definition is as below (using Script Table As--Create) :
[Id] [int] IDENTITY(1,1) NOT NULL,
[MinSalary] [decimal](18, 2) NOT NULL,
[MaxSalary] [decimal](18, 2) NOT NULL,
[CreatedBy] [varchar](50) NULL,
[TableName] [varchar](50) NULL,
[TierName] [varchar](50) NOT NULL,
[CreatedOn] [datetime] NULL,
CONSTRAINT [PK__Zimra__3214EC07397C51AA] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
And the stored procedure is as below:
CREATE PROCEDURE [dbo].[SaveZimraTable]
#TableName varchar(50),
#TierName varchar(50),
#MinSalary decimal(18,2),
#MaxSalary decimal(18,2),
#CreatedBy varchar(50),
#CreatedOn datetime
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
INSERT INTO Zimra VALUES (#TableName,#TierName,#MinSalary,#MaxSalary,#CreatedBy,#CreatedOn)
END
GO
Always specify the columns list in an insert statement. Otherwise, you must specify values for all the columns (except identity columns) and you must do it in the correct order - which is clearly not the case in your statement. Also, you run the risk of breaking the statement if you change the table structure - either by adding a column or switching columns order.
INSERT INTO Zimra (TableName, TierName, MinSalary, MaxSalary, CreatedBy, CreatedOn)
VALUES (#TableName,#TierName,#MinSalary,#MaxSalary,#CreatedBy,#CreatedOn)
Also, as noted in the comments, do not use AddWithValues to add parameters to your command object - instead, use Add:
cmd.Parameters.Add("#TableName", SqlDbType.VarChar).Value = zimra.TableName;
// do the same for all parameters.
I have a question with regards to performance currently I have a table that is having trouble with query performance whenever the table rows in already millions of record.
This is the table:
CREATE TABLE [dbo].[HistorySampleValues]
(
[HistoryParameterID] [int] NOT NULL,
[SourceTimeStamp] [datetime2](7) NOT NULL,
[ArchiveTimestamp] [datetime2](7) NOT NULL CONSTRAINT [DF__HistorySa__Archi__2A164134] DEFAULT (getutcdate()),
[ValueStatus] [int] NOT NULL,
[ArchiveStatus] [int] NOT NULL,
[IntegerValue] [bigint] SPARSE NULL,
[DoubleValue] [float] SPARSE NULL,
[StringValue] [varchar](100) SPARSE NULL,
[EnumNamedSetName] [varchar](100) SPARSE NULL,
[EnumNumericValue] [int] SPARSE NULL,
[EnumTextualValue] [varchar](256) SPARSE NULL
) ON [PRIMARY]
CREATE CLUSTERED INDEX [Source_HistParameterID_Index] ON [dbo].[HistorySampleValues]
(
[HistoryParameterID] ASC,
[SourceTimeStamp] ASC
) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
GO
It's fairly flat with a clustered index on HistoryParameterID and SourceTimeStamp.
This is the stored procedure that I'm using
SET NOCOUNT ON;
DECLARE #SqlCommand NVARCHAR(MAX)
SET #SqlCommand = 'SELECT HistoryParameterID,
SourceTimestamp, ArchiveTimestamp,ValueStatus,ArchiveStatus,
IntegerValue,DoubleValue,StringValue,EnumNumericValue,
EnumTextualValue,EnumNamedSetName
FROM [HistorySampleValues] WITH(NOLOCK)
WHERE ([HistoryParameterID] =' + #ParamIds + '
AND
[SourceTimeStamp] >= ''' + CONVERT(VARCHAR(30),#StartTime, 25) + '''
AND
[SourceTimeStamp] <= ''' + CONVERT(VARCHAR(30),#EndTime, 25) + ''')
AND ValueStatus = ' + #ValueStatus
EXECUTE( #SqlCommand )
As you can see the HistoryParameterID and SourceTimestamp are being used as the parameters for the first query. And retrieving 8hrs worth of records which is ~28k records, it returns with an erratic performance, 1.8seconds - 700ms
Will the design scale? whenever it reaches 77 billion records? or is there any strategy to be used? the version of SQL Server is Standard Edition so there is no partitioning, columnstore to be used. Or have I reached the maximum performance of SQL Server Standard Edition?
this is the updated stored proc
#ParamIds int,
#StartTime datetime,
#EndTime datetime,
#ValueStatus int
AS
BEGIN
SET NOCOUNT ON;
SELECT HistoryParameterID,
SourceTimestamp, ArchiveTimestamp,ValueStatus,ArchiveStatus,
IntegerValue,DoubleValue,StringValue,EnumNumericValue,
EnumTextualValue,EnumNamedSetName
FROM [HistorySampleValues] WITH(NOLOCK)
WHERE
HistoryParameterID = #ParamIds
AND (SourceTimeStamp >= #StartTime AND SourceTimeStamp <=#EndTime)
AND (#ValueStatus = -1 OR ValueStatus = #ValueStatus)
I got a 1.396 second client processing time in retrieving 41213 rows to a ~849600000 rows in the table.
is there a way to improve this?
Everytime you execute a new SQL command, it has to be compiled by the MS SQL Server. If you re-use the command, you save on compilation time. You need to directly execute the command in the stored procedure something like this, which should allow compilation and give you more consistent results.
SELECT ...
WHERE ([HistoryParameterID] = #ParamIds
AND [SourceTimeStamp] >= #StartTime
AND [SourceTimeStamp] <= #EndTime
AND ValueStatus = #ValueStatus
This will give you also an opportunity to monitor the performance of the command.
I'm already sorry ... I am quite new to this whole posting stuff, but I am trying my best ...
I got two tables ... 'Customer' and 'Rooms' ... a single Customer with a UNIQUE CU_ID is staying in a room (with a UNIQUE ROOM_ID, unfortunately for me, sometimes there are 2 or three CU_ID staying in the same Room ... they usually check in at the same day though, so the CheckInDate should be the same ...
When they check in and the RoomNo is entered on the 'Customer'-Table I would like the Bit-Field 'Occupied' in the 'Rooms'-Table to be set to "TRUE". That part I got done with a Trigger (see below) ...
The trick is when they are checking out ... If a User manually marks the "Occupied"-(Bit)Field for that Room-ID as "FALSE", then I would like to set the DepartDate on the Customer-Table for ANY Customer staying in that room at the MOMENT to Getdate().
Here's my tables, Trigger, and some test data:
CREATE TABLE [dbo].[Rooms](
[Room_ID] [int] IDENTITY(1,1) NOT NULL,
[Room_No] [nvarchar](50) NULL,
[Occupied] [bit] NULL,
[CheckInDate] [int] NULL,
CONSTRAINT [PK_Rooms] PRIMARY KEY CLUSTERED
(
[Room_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Customer](
[CU_ID] [int] IDENTITY(5000,1) NOT NULL,
[CheckInDate] [datetime] NULL,
[RoomNo] [int] NOT NULL,
[Nights_Booked] [int] NULL,
[DepartDate] [datetime] NULL,
CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED
(
[CU_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Customer] WITH CHECK ADD CONSTRAINT [FK_Customer_Rooms] FOREIGN KEY([RoomNo])
REFERENCES [dbo].[Rooms] ([Room_ID])
GO
ALTER TABLE [dbo].[Customer] CHECK CONSTRAINT [FK_Customer_Rooms]
GO
-- 2 Tables created including PK/FK Relationship
Here's my Trigger for the first step ... updating the bit column Occupied to True when Room_ID is used for new Check-In:
Create TRIGGER [dbo].[Occupied]
ON [dbo].[Customer]
FOR INSERT
NOT FOR REPLICATION
AS
BEGIN
IF TRIGGER_NESTLEVEL() > 1
RETURN
UPDATE Rooms
SET [Occupied] = 'True'
FROM Rooms r
JOIN Customer cu
ON cu.[RoomNo] = r.[Room_ID]
Join INSERTED INS
ON cu.[RoomNo] = INS.[RoomNo]
END
GO
I enter some test data into both of them ...
SET IDENTITY_INSERT Rooms ON
INSERT INTO Rooms
(Room_ID, Room_No, Occupied)
SELECT 1, 'A14', 0 UNION ALL
SELECT 2, 'B2', 0 UNION ALL
SELECT 3, 'C3', 0 UNION ALL
SELECT 4, 'D8', 0 UNION ALL
SELECT 5, 'K9', 0
SET IDENTITY_INSERT Rooms OFF
GO
SET IDENTITY_INSERT Customer ON
INSERT INTO Customer
(CU_ID, CheckInDate, RoomNo, Nights_Booked, DepartDate)
SELECT 5000, '2013-05-10', 1, 4, NULL UNION ALL
SELECT 5001, '2013-05-10', 1, 4, NULL UNION ALL
SELECT 5002, '2013-05-10', 2, 2, NULL UNION ALL
SELECT 5003, '2013-05-10', 3, 3, NULL UNION ALL
SELECT 5004, '2013-05-11', 4, 4, NULL UNION ALL
SELECT 5005, '2013-05-11', 4, 4, NULL UNION ALL
SELECT 5006, '2013-05-11', 4, 4, NULL
SET IDENTITY_INSERT Customer OFF
-- Test Data entered in rows on 'Rooms' and 'Customer'-Tables
The Trigger works fine and it updates all the Records with the same Room_ID (RoomNo respectively on Customer Table).
I tried to solve my problem with other Triggers. And I get SQL Server to enter the Depart-Date based on the Check-In-Date of the specific Customer, if I pass that one on to the Room-Table. Unfortunately it only updates the Data with the 1st Entry made for that specific Room_ID on the Rooms-Table ... and it seems awkwardly much passing back and forth between the two tables. I guess I need a Stored Procedure/Function to actually accomplish that:
On Insert of Customer Record pass NEWEST CheckInDate and Insert into Room-Table Field CheckInDate
When Rooms.Occupied is marked as 'False', set the Check-Out-Date for all CU_ID with Customer.RoomNo = Rooms.Room_ID AND Customer.CheckInDate = Rooms.CheckInDate to GETDATE() ...
I struggle with the first part - how to pass the CheckInDate on Insert and if a value is existing update it with the newer date ...
No idea, again ... I'm all new :)
Thanks for any help in advance !!!
Welcome to StackOverflow. In the future, it would be very helpful to us if you keep the examples short. In this case, for example, all we would have needed is a few columns from each table (none of the options/constraints).
You shouldn't be manually updating bits. Use stored procedures instead.
CREATE PROCEDURE [dbo].[usp_CheckoutRoom] (
#RoomID
)
AS
UPDATE [dbo].[Rooms]
SET [Occupied] = 0
WHERE [Room_ID] = #RoomID
UPDATE [dbo].[Customer]
SET [DepartDate] = GETDATE()
WHERE [RoomNo] = #RoomID
END
I'm assuming you're still working on the design of your system, but what happens if a single customer checks out multiple rooms? You need a Customer/Room cross reference table.
[dbo].[Customer]
[dbo].[Room]
[dbo].[CustomerRoom]
Also note that it isn't obvious that [dbo].[Customer].[RoomNo] is actually the [RoomID].
I have a table called tbRep in my database
I have 3 schemas on the the SQL Server database
X, Y, Z
now X & Y have tables called X.tbRep & Y.tbRep
However, when I try use the CREATE To script from e.g. X.tbRep and try to create one for the new schema Z, it throws an error saying,
Msg 2714, Level 16, State 6, Line 2
There is already an object named 'tbRep' in the database.
What am I doing wrong here?
I'm sure that there are Z.tbRep doesn't exist
CREATE to script
USE [Info]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [Z].[tbRep](
[ReplicaGroup] [varchar](50) NOT NULL,
[RunFrequencyUnit] [char](1) NOT NULL,
[Enabled] [bit] NOT NULL,
[LastRun] [datetime] NOT NULL,
[RunFrequency] [int] NOT NULL,
[ReplicationWindowType] [char](1) NOT NULL,
[ReplicationWindowSize] [tinyint] NOT NULL,
CONSTRAINT [PK_tbReplicaGroups] PRIMARY KEY CLUSTERED
(
[ReplicaGroup] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [Z].[tbReplicaGroups] ADD CONSTRAINT [DF_tbReplicaGroups_ReplicationWindowType] DEFAULT ('D') FOR [ReplicationWindowType]
GO
ALTER TABLE [Z].[tbReplicaGroups] ADD CONSTRAINT [DF_tbReplicaGroups_ReplicationWindowSize] DEFAULT ((1)) FOR [ReplicationWindowSize]
GO
--Checks to see if the table doesn't already exist, if not add your creation script
if not exists (select name from sys.tables where name = 'tpRep')
BEGIN
--Table Creation code goes here
END
Can you execute this before CREATE TABLE statement and let us know if you are getting anything?
select *
from sys.all_objects
where sys.all_objects.name = 'tbRep' and
sys.all_objects.type = 'U' and
sys.all_objects.schema_id = (select schema_id from sys.schemas where sys.schemas.name = 'Z')
In SQL Server 2008 R2, I have a simple table with the following columns definitions:
Id (PK ,int , not null)
MeterId (FK , int ,not null)
InstallDate(DateTime, not null)
Image(NVarCharMax, null)
Number (int , not null)
Comments(NVarChar(300), null)
And Id column is set as Identity .
When I run:
insert into Transmitters (MeterId, Number, InstallDate)
values (952, 777 , '2013-02-21')
I get the duplicate key error.
There is no other transmitter with id 777 ,
There is a meter with id 952.
This started happening in more than 1 table of my DB.
Any suggestions would be most appriceated.
The entire table script is:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Transmitters](
[Id] [int] IDENTITY(1,1) NOT NULL,
[MeterId] [int] NOT NULL,
[InstallDate] [datetime] NOT NULL,
[Image] [nvarchar](max) NULL,
[Number] [int] NOT NULL,
[Comments] [nvarchar](300) NULL,
CONSTRAINT [PK_Transmitters] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Transmitters] WITH CHECK ADD CONSTRAINT [FK_Transmitter_Meter] FOREIGN KEY([MeterId])
REFERENCES [dbo].[Meter] ([Id])
GO
ALTER TABLE [dbo].[Transmitters] CHECK CONSTRAINT [FK_Transmitter_Meter]
GO
Ok , thanks guys you've been most helpful.
I've checked my identity current value using:
USE Name_Of_The_DB
GO
DBCC CHECKIDENT (‘Name_Of_The_Table’)
GO
It was indeed the cause of the problem that some rows had higher Id values than
the current identity.
Thand I inserted a row to update the current identity value:
set identity_insert YourTable ON
--Insert my row
set identity_insert YourTable OFF
Thanks :)