Inserting into a joined view SQL Server - sql-server

This is a question more about design than about solving a problem.
I created three tables as such
CREATE TABLE [CapInvUser](
[UserId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](150) NOT NULL,
[AreaId] [int] NULL,
[Account] [varchar](150) NULL,
[mail] [varchar](150) NULL,
[UserLevelId] [int] NOT NULL
)
CREATE TABLE [CapInvUserLevel](
[UserLevelId] [int] IDENTITY(1,1) NOT NULL,
[Level] [varchar](50) NOT NULL
)
CREATE TABLE [CapInvUserRegistry](
[UserRegistryId] [int] IDENTITY(1,1) NOT NULL,
[UserLevelId] int NOT NULL,
[DateRegistry] DATE NOT NULL,
[RegistryStatus] VARCHAR(50) NOT NULL,
)
With a view that shows all the data on the first table with "AreaId" being parsed as the varchar identifier of that table, the UserLevel being parsed as the varchar value of that table, and a join of the registry status of the last one.
Right now when I want to register a new user, I insert into all three tables using separate queries, but I feel like I should have a way to insert into all of them at the same time.
I thought about using a stored procedure to insert, but I still don't know if that would be apropiate.
My question is
"Is there a more apropiate way of doing this?"
"Is there a way to create a view that will let me insert over it? (without passing the int value manually)"
--This are just representations of the tables, not the real ones.
-- I'm still learning how to work with SQL Server properly.
Thank you for your answers and/or guidance.

The most common way of doing this, in my experience, is to write a stored procedure that does all three inserts in the necessary order to create the FK relationships.
This would be my unequivocal recommendation.

Related

SQL Pivot with multiple joins

The SQL Pivot command seems difficult at least. I've read a lot about it, and been tinkering with this query for a while, but all I get are really obscure error messages that don't help, like "The column name 'Id' was specified multiple times.." or "The multi-part identifier X could not be bound."
Our database collects client answers to questions. I'd like to create a table which contains a row for each client, and columns for each question (ID) they've answered and the AVG ResponseTime across all times that user has logged in. This is made more difficult as the UserId isn't directly stored in the UserSessionData table, it's stored in the UserSession table, so I have to do a join first, which seems to complicate the issue.
The tables I'm trying to pivot are roughly of the following form:
CREATE TABLE [dbo].[UserSessionData](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserSessionId] [int] NOT NULL,
[UserWasCorrect] [bit] NULL,
[ResponseTime] [float] NULL,
[QuestionId] [int] NULL)
--This table contains user answers to a number of questions.
CREATE TABLE [dbo].[UserSession](
[Id] [int] IDENTITY(1,1) NOT NULL,
[UserId] [int] NOT NULL,
[SessionCode] [nvarchar](50) NOT NULL)
--This table contains details of the user's login session.
CREATE TABLE [dbo].[Question](
[Id] [int] IDENTITY(1,1) NOT NULL,
[QuestionText] [nvarchar](max) NOT NULL,
[GameId] [int] NOT NULL,
[Description] [nvarchar](max) NULL)
--This table contains question details
I'll continue trying to mangle a solution, but if anyone can shed any light (or suggest an easier method than PIVOT to achieve the desired result), then that would be great.
Cheers
It's because you've got the same column names in multiple tables so after you've done the join the pivot sees multiple columns all the same name. Have a look at my example below:
SELECT
*
FROM (
SELECT
usd.Id AS usdId
,UserSessionId
,UserWasCorrect
,ResponseTime
,QuestionId
,us.Id AS usId
,SessionCode
,UserId
,Description
,GameId
,qu.Id AS quId
,QuestionText
FROM #UserSessionData usd
LEFT JOIN #UserSession us
ON usd.UserSessionId = us.Id
LEFT JOIN #Question qu
ON usd.QuestionId = qu.Id
) AS tbl PIVOT (
-- As no example data was provided 'quest' & 'voyage are just random values I put in. Change the pivot statement to match what you want
MIN(ResponseTime) FOR SessionCode IN (quest, voyage)
) AS pvt
'quest' and 'voyage' are example data of the rows contents in the Column SessionCode. This will need to be changed to your columns contents. In PIVOTs and UNPIVOTs you cannot use a query to get these values and they have to be statically put in. You could use dynamic SQL to generate the values however this is usually heavily advised against

GUID_PK in SQL Server

When I execute this query, I am getting an error
Cannot find data type dbo.GUID_PK
For this should I create table for CandidateRoleID or what else should I do here?
But, when I googled it I found it saying SQL Server stores GUID. How could I access it or what is the correct way of declaring this table? I searched in google about GUID_PK.
But didn't find any syntax or explanation. Thanks in advance.
CREATE TABLE [dbo].[tbl]
(
[CandidateRoleID] [dbo].[GUID_PK] NOT NULL,
[CandidateID] [uniqueidentifier] NOT NULL,
[RoleID] [int] NOT NULL
);
The SQL server data type for a GUID is UNIQUEIDENTIFIER.
Your script should be:
CREATE TABLE [dbo].[tbl](
[CandidateRoleID] [uniqueidentifier] NOT NULL,
[CandidateID] [uniqueidentifier] NOT NULL,
[RoleID] [int] NOT NULL,
CONSTRAINT PK_Tbl PRIMARY KEY (CandidateRoleID));
If you want it to be 'automatically' created, similar to an integer identity column, give it a default:
CREATE TABLE [dbo].[tbl](
[CandidateRoleID] [uniqueidentifier] NOT NULL DEFAULT NEWID(),
[CandidateID] [uniqueidentifier] NOT NULL,
[RoleID] [int] NOT NULL,
CONSTRAINT PK_Tbl PRIMARY KEY (CandidateRoleID));
CREATE TABLE [dbo].[tbl](
[CandidateRoleID] [uniqueidentifier] primary key NOT NULL,
[CandidateID] [uniqueidentifier] NOT NULL,
[RoleID] [int] NOT NULL,
);
In SQL server GUID is uniqueidentifier data type.
There is no data type 'GUID_PK' in sql server.
GUID is an acronym for Global Unique ID(entifier) and is a unique 16
byte number. The term GUID and UNIQUEIDENTIFIER are often
interchangeable within the SQL Server community.
If you need to auto-generate uniqueidentifier value in your table during data insert, the consider adding default value to the uniqueidentifier data-type.
CREATE TABLE #tbl(
[CandidateRoleID] [uniqueidentifier] NOT NULL DEFAULT NEWID(),
[CandidateID] [uniqueidentifier] NOT NULL DEFAULT NEWID(),
[RoleID] [int] NOT NULL);
GO
INSERT INTO #tbl (ROLEID) SELECT (1)
CandidateRoleID CandidateID RoleID
F20AE15E-8D97-4042-8AA8-DD7BCB0EB6D6 FAE29358-BD34-4BFE-800B-E332375E020E 1

Slow on Retrieving data from 38GB SQL Table

I am looking for some advise. I have a SQL Server table called AuditLog and this table records any action/changes that happens to our DB from our web application.
I am trying to build some reports and anytime I try to pull data from this table it makes my query run from seconds to 10mins+. Just doing a
select * from dbo.auditlog
takes about 2hours+.
The table has 77 million rows and is growing. Anyhow, only thoughts at this moment is to do an index but that would slow down inserts. Not sure how much that would affect performance but have held back on it. Other thoughts were to partition the table or do an index view but we are running SQL Server 2014 Standard Edition and those options are not supported.
Here is the table create statement:
CREATE TABLE [dbo].[AuditLog]
(
[AuditLogId] [uniqueidentifier] NOT NULL,
[UserId] [uniqueidentifier] NULL,
[EventDateUtc] [datetime] NOT NULL,
[EventType] [char](1) NOT NULL,
[TableName] [nvarchar](100) NOT NULL,
[RecordId] [nvarchar](100) NOT NULL,
[ColumnName] [nvarchar](100) NOT NULL,
[OriginalValue] [nvarchar](max) NULL,
[NewValue] [nvarchar](max) NULL,
[Rams1RecordID] [uniqueidentifier] NULL,
[Rams1AuditHistoryID] [uniqueidentifier] NULL,
[Rams1UserID] [uniqueidentifier] NULL,
[CreatedBy] [uniqueidentifier] NULL,
[CreatedDate] [datetime] NULL DEFAULT (getdate()),
[OriginalValueNiceName] [nvarchar](100) NULL,
[NewValueNiceName] [nvarchar](100) NULL,
CONSTRAINT [PK_AuditLog]
PRIMARY KEY CLUSTERED ([TableName] ASC, [RecordId] ASC, [AuditLogId] ASC)
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[AuditLog] WITH NOCHECK
ADD CONSTRAINT [FK_AuditLog_User]
FOREIGN KEY([UserId]) REFERENCES [dbo].[User] ([UserID])
GO
ALTER TABLE [dbo].[AuditLog] CHECK CONSTRAINT [FK_AuditLog_User]
GO
ALTER TABLE [dbo].[AuditLog] WITH NOCHECK
ADD CONSTRAINT [FK_AuditLog_UserCreatedBy]
FOREIGN KEY([CreatedBy]) REFERENCES [dbo].[User] ([UserID])
GO
ALTER TABLE [dbo].[AuditLog] CHECK CONSTRAINT [FK_AuditLog_UserCreatedBy]
GO
With something that big there are a couple of things you might try.
The first thing you need to do is define how you accessing the table MOST of the time and index accordingly.
I would hope you are not do a select * from AuditLog without any filtering for a reporting solution - it shouldn't even be an option.
Finally, instead of indexed views or partitioning, you might consider a partitioned view.
A partitioned view is basically breaking your table up, physically into smaller meaningful tables - based on date or type or object or however you are MOST often accessing it. Each table is then indexed separately giving you much better stats and if you in 2012 or higher you can take advantage of ColumnStore, assuming you use something like a DATE to group the data.
Create a view that spans all of the tables and then report based on the view. Since you already grouped your data by how you MOST often will access it, your filter will act similarly to partition exclusion and get you to your data faster.
Of course this will result in a little more maintenance and some code change, but be well worth the effort if you are storing that much data and more in a single table.

Row update if row exists. Insert it if row doesn't exist

I'm developing a SQL SERVER 2012 express and developer solution.
I will receive an xml in an stored procedure. In the stored procedure I will parse the xml and insert its data into a table.
My problem here is that in this xml could contain data that exists on the table, and I need to update the data on the table with the new one.
I don't want to check if each row in xml exists on the table.
I think I can use IGNORE_DUP_KEY but I'm not sure.
How can I update or insert new data without checking it?
This is the table where I want to insert (or update) the new data:
CREATE TABLE [dbo].[CODES]
(
[ID_CODE] [bigint] IDENTITY(1,1) NOT NULL,
[CODE_LEVEL] [tinyint] NOT NULL,
[CODE] [nvarchar](20) NOT NULL,
[COMMISIONING_FLAG] [tinyint] NOT NULL,
[IS_TRANSMITTED] [bit] NOT NULL,
[TIMESPAN] [datetime] NULL,
[USERNAME] [nvarchar](50) NULL,
[SOURCE] [nvarchar](50) NULL,
[REASON] [nvarchar](200) NULL
CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED
(
[CODE_LEVEL] ASC,
[CODE] ASC
)
)
The "IGNORE_DUP_KEY" parameter ,is ignore inserting new row, if he is already exists, but it is not dealing with update in case it exists.
the solution to your request is by MERGE or DML operation (INSERT/UPDATE/DELETE) .
BTW,
The parameter "IGNORE_DUP_KEY" is covering existsnce for the index key only (index column).

Reuse t-sql table variable or clone its structure

I'm writing stored procedure to paginate results of a different stored procedure. I do it by executing the stored procedure and inserting results into the table variable:
DECLARE #allResults table
(
[ID] [int] NOT NULL,
[DESCRIPTION] [varchar](MAX) NULL,
[COL1] [VARCHAR],
[COL2] [VARCHAR],
...
);
INSERT #allResults Exec [dbo].[GetResults];
I need to filter the results and store them somewhere because I will use filtered results in at least two places: to count all the records and to actually paginate. Ideally I'd like to reuse the #allResults table as I won't need its content anymore after filtering. Something similar to:
#allresults = #allresults where [DESCRIPTION] like '%keyword%'
I'm not exactly sure how can I truncate table in the same moment as I filter it. That's why I created second table variable with the same structure:
DECLARE #filteredResults table
(
[ID] [int] NOT NULL,
[DESCRIPTION] [varchar](MAX) NULL,
[COL1] [VARCHAR],
[COL2] [VARCHAR],
...
);
It's not a bad solution, and it works. But I wonder could I reuse the definition of a table variable? Something that would look like:
DECLARE #filteredResults, #allResults table
(
[ID] [int] NOT NULL,
[DESCRIPTION] [varchar](MAX) NULL,
[COL1] [VARCHAR],
[COL2] [VARCHAR],
...
);
Is there a way to do it? Maybe there's a way to clone table variable? I guess simultaneous delete and filtering could be achieved using delete with output clause but I'm not exactly sure how should I write it.
I hate to repeat code. Maybe there's a simple solution you know of :)
You can create your own user table type:
CREATE TYPE dbo._t_test AS TABLE(
[ID] [int] NOT NULL,
[DESCRIPTION] [varchar](MAX) NULL,
[COL1] [VARCHAR],
[COL2] [VARCHAR]
)
GO
And then create table variables like this:
DECLARE #filteredResults dbo._t_test
, #allResults dbo._t_test

Resources