Database Design: Table structure - sql-server

I've excel form which contain macro that can pull data from SQL Server and display info on the excel form. Users can update the form and macro will write changed back to SQL Server.
This is the excel form. Users need to input the values for those highlighted on yellow color. Example John enter user field as 'JOHN' follow by region 'LATAM' , year '2016' and month '3'. Once it done, John would click an 'Retrieve' button to pull all data from SQL Server where Region = LATAM, Year=2016 and Month = 3. All the related info would display on field Area, Region, Mgmt, CompanyCode, AcctUnit, Account and Value (It could have multiple rows of records and users are not allow to edit these records). Now John need to input value for field Comments. Once he completed, John would click 'Save' button and excel macro would write comments value to SQL Server
Here the table structure that excel macro will read and write
CREATE TABLE [dbo].[Sales](
[Region] [varchar](10) NOT NULL,
[Area] [varchar](10) NOT NULL,
[Mgmt] [varchar](10) NOT NULL,
[CompanyCode] [int] NOT NULL,
[AcctUnit] [varchar](7) NOT NULL,
[Account] [varchar](10) NOT NULL,
[Comment] [varchar](100) NULL,
[Year] [int] NULL,
[Jan] [float] NULL,
[Feb] [float] NULL,
[Mar] [float] NULL,
[Apr] [float] NULL,
[May] [float] NULL,
[Jun] [float] NULL,
[Jul] [float] NULL,
[Aug] [float] NULL,
[Sep] [float] NULL,
[Oct] [float] NULL,
[Nov] [float] NULL,
[Dec] [float] NULL,
[SYS_CreatedBy] [varchar](15) DEFAULT SYSTEM_USER,
[SYS_CreatedDate] [datetime] DEFAULT GETDATE(),
[SYS_ModifiedBy] [varchar](15) DEFAULT SYSTEM_USER,
[SYS_ModifiedDate] [datetime] DEFAULT GETDATE(),
CONSTRAINT [PK_Sales] PRIMARY KEY NONCLUSTERED
(
Region ASC,
Area ASC,
Mgmt ASC,
CompanyCode ASC,
AcctUnit ASC,
Account ASC,
)
)
Based on above table structure, how can other users put his/her comments while it doesn't affected those comments that John already updated to SQL Server ? Example, John already input his comments and has been updated to SQL Server, now Alice pull same data from SQL Server where region = LATAM, Year = 2016 and Month = 3. She should get same data as John did except comments field, which in this case should be blank instead of John's comment.
Based on above table design, the comment's value will keep changing by different users. How to redesign table structure so comment can be unique to each users?

I would create a Comments table, and relate it to the Sales table through a foreign key.
To that end, I would add a surrogate key to the Sales table, so that you don't need to add all those PK columns to your Comments table.

Related

SQL Azure - Unable to query External Table from SSMS - Error Invalid object name 'dbo.AuditLogSource

Is there someone who can help me figure out why I cannot query an external table that I created using my SQL Server Mgt Studio. I can see the external table if I expand External Tables but if I Right click and Select Top 1000 Rows I get an error that Invalid object name 'dbo.AuditLogSource'.
I am trying to copy a certain amount of data from an audit log table in DB1.AuditLog into ArchiveDB.AuditLog. I've followed the tutorials on how to use Elastic Queries to archive this simple task but I am now stuck at this point where I should query from the external table created locally in my ArchiveDB. Here's the process I followed maybe I made a mistake somewhere please help me:
CREATE MASTER KEY ENCRYPTION BY PASSWORD = '2019MoxvE!';
--DROP MASTER KEY;
CREATE DATABASE SCOPED CREDENTIAL SQL_Credential
WITH IDENTITY = 'myusername',
SECRET = '2019MoxvE!';
--DROP DATABASE SCOPED CREDENTIAL SQL_Credential;
CREATE EXTERNAL DATA SOURCE RemoteReferenceData
WITH
(
TYPE=RDBMS,
LOCATION='ourserver.database.windows.net',
DATABASE_NAME='DB1',
CREDENTIAL= SQL_Credential
);
--DROP EXTERNAL DATA SOURCE RemoteReferenceData;
CREATE EXTERNAL TABLE [dbo].[AuditLogSource]
(
[Id] [int] NOT NULL,
[Userid] [int] NOT NULL,
[ObjectId] [int] NULL,
[CreatedOn] [datetime] NOT NULL,
[ModifiedOn] [datetime] NOT NULL,
[ModifiedBy] [varchar](150) NOT NULL,
[Type] [int] NOT NULL,
[ActionTable] [varchar](50) NOT NULL,
[IsAjaxRequest] [bit] NOT NULL,
[Parameters] [varchar](max) NOT NULL,
[Controller] [varchar](50) NOT NULL,
[Action] [varchar](50) NOT NULL,
[Comments] [varchar](max) NULL,
[BeforeImage] [varchar](max) NULL,
[AfterImage] [varchar](max) NULL,
[Browser] [varchar](max) NULL
)
WITH (DATA_SOURCE = [RemoteReferenceData]);
--DROP EXTERNAL TABLE [dbo].[AuditLogSource];
INSERT INTO [dbo].[AuditLog]
SELECT al.* FROM [dbo].[AuditLogSource] al WHERE al.[CreatedOn] <= '2020/12/31' AND
NOT EXISTS(SELECT 1 FROM [dbo].[AuditLog] al1 WHERE al1.Id=al.Id);
If you see on below screenshot, you can see that there are no errors being highlighted on this query which means that the query window does recognise that the table AuditLogSource does exists but if I run the query it complains that it does not exists. I can also confirm that the user I am logged into the database with is the admin user and own of both DB1 and ArchiveDB What can I do to make this work?
Thanks in advance.
Make sure you're using the correct database also if you create a new SQL Server object, your newly created object does not get updated in the IntelliSense Local Cache and due to this, it shows an Invalid object name: dbo.AuditLogSource.Please follow below reference.
Ex: [DatabaseName].[Schema].[TableName]
Try:
Edit -> IntelliSense -> Refresh Local Cache or Ctrl + shift + R
Reference:
Sql server invalid object name - but tables are listed in SSMS tables list
https://learn.microsoft.com/en-us/sql/t-sql/statements/create-external-table-transact-sql?view=sql-server-ver16&tabs=dedicated
Ok so I will post an answer to this question in case another person comes across the same/similar problem. So I only made 1 mistake in creating the External Table and this is because of the tutorials and other answers I saw on this very platform.
CREATE EXTERNAL TABLE [dbo].[AuditLogSource]
(
[Id] [int] NOT NULL,
[Userid] [int] NOT NULL,
[ObjectId] [int] NULL,
[CreatedOn] [datetime] NOT NULL,
[ModifiedOn] [datetime] NOT NULL,
[ModifiedBy] [varchar](150) NOT NULL,
[Type] [int] NOT NULL,
[ActionTable] [varchar](50) NOT NULL,
[IsAjaxRequest] [bit] NOT NULL,
[Parameters] [varchar](max) NOT NULL,
[Controller] [varchar](50) NOT NULL,
[Action] [varchar](50) NOT NULL,
[Comments] [varchar](max) NULL,
[BeforeImage] [varchar](max) NULL,
[AfterImage] [varchar](max) NULL,
[Browser] [varchar](max) NULL
)
WITH
(
DATA_SOURCE = [RemoteReferenceData],
SCHEMA_NAME = 'dbo', -- I missed this part
OBJECT_NAME = 'AuditLog' -- I missed this part
);
So my problem was that I had omitted the SCHEMA_NAME = 'dbo' and OBJECT_NAME = 'AuditLog' which makes a reference to the AuditLog table in DB1. With my OP, Azure was making a reference to AuditLogSource in DB1 which obviously doesn't exist hence I get the error I was getting. BUT, it would help if the query failed in the first place coz that would've highlighted that there was something wrong somewhere. Anyway, I hope this helps someone.

Need help storing a table's schema in a variable in SSIS

I'm making an SSIS solution to store students' marks in a data warehouse. The OLTP database has different schemas to separate the campuses. Both the OLTP and data warehouse has a "Marks" table, but the data warehouse has an additional CampusID column that is a foreign key that references a table called "Campus" that stores a list of the college's campuses. I'm looking for a way to store a table's schema name in a variable, evaluate it to decide what the CampusID must be, and insert that CampusID in the "Marks" table. E.g if the OLTP table's schema is "AucklandPark", the CampusID is 1 and that gets inserted into the "Marks" table.
This is for a project we have to do. I found this solution SSIS - Using the SQL Server Schema Name as a Variable for Queries and Procedure Calls, but it's not dynamic; the project variable in the solution has a fixed value and I'd have to create fifteen different packages to get the desired result.
The definition for the "Marks" table in the OLTP database looks like this:
CREATE TABLE AucklandPark.Marks(
MarkID INT PRIMARY KEY IDENTITY,
StudentID INT NOT NULL FOREIGN KEY REFERENCES AucklandPark.StudentInfo(StudentID) ON DELETE CASCADE,
FA_1 TINYINT CHECK(FA_1 BETWEEN 0 AND 100),
FA_2 TINYINT CHECK(FA_2 BETWEEN 0 AND 100),
FA_3 TINYINT CHECK(FA_3 BETWEEN 0 AND 100),
SA_1 TINYINT CHECK(SA_1 BETWEEN 0 AND 100),
SA_2 TINYINT CHECK(SA_2 BETWEEN 0 AND 100),
INT_1 TINYINT CHECK(INT_1 BETWEEN 0 AND 100),
INT_2 TINYINT CHECK(INT_2 BETWEEN 0 AND 100),
INT_3 TINYINT CHECK(INT_3 BETWEEN 0 AND 100)
);
GO
And the definition for the data warehouse looks like this (using script generation):
CREATE TABLE [dbo].[Marks](
[DW_MarkID] [int] IDENTITY(1,1) NOT NULL,
[MarkID] [int] NOT NULL,
[DW_StudentID] [int] NOT NULL,
[CourseID] [tinyint] NOT NULL,
[CampusID] [tinyint] NOT NULL,
[DW_FacilitatorID] [int] NOT NULL,
[DateID] [int] NOT NULL,
[FA_1] [tinyint] NULL,
[FA_2] [tinyint] NULL,
[FA_3] [tinyint] NULL,
[SA_1] [tinyint] NULL,
[SA_2] [tinyint] NULL,
[INT_1] [tinyint] NULL,
[INT_2] [tinyint] NULL,
[INT_3] [tinyint] NULL,
(I'm leaving out all the constraints it adds afterwards)
I solved the problem by adding a column for CampusID.

SSMS 2014 Design Does not show column

I have created a table which has the columns
Id, name, CountryId,CreatedOn,CreatedBy,updatedOn,UpdatedBy
but when i see the design, there is no CountryId.
When i see script of the created table, it shows CountryId
the script is as follows --
CREATE TABLE [dbo].[State](
[Id] [int] NOT NULL,
[name] [nvarchar](255) NOT NULL,
[CountryId] [int] NOT NULL,
[CreatedOn] [datetime] NULL,
[CreatedBy] [nvarchar](50) NULL,
[UpdatedOn] [datetime] NULL,
[UpdatedBy] [nvarchar](50) NULL,
);
Also, When I right click and select top 100 rows, i find CountryId there. (The following image)
What can be the reason that the design is not showing a column ??
EDIT:
As suggested by shnugo, i was able to solve it after closing and re-opening SSMS 2014

SQL Server : submit leave application

I have just started learning SQL and I'm really struggling. I have a very simple employees table and trying to link it with a leave table.
CREATE TABLE [MOUNTAIN].[VOLUNTEER]
(
[EMPLOYEE_ID] [int] identity (1,1) not null,
[NAME] [nvarchar] (20) not null,
[PHONENUMBER] [nvarchar] (20) not null,
[ADDRESS] [NVARCHAR] (200) NOT NULL
);
CREATE TBALE [EMPLOYEE_LEAVE]
(
[LEAVE_ID] [int] identity (1,1) not null,
[EMPLOYEE_ID] [int] not null,
[START_DATE] [DATE] not null,
[END_DATE] [DATE] not null,
);
I want these to be linked so an employee can enter start date and end date and submit it online and it will update in SQL Server.
I'm sure this is very simple and i have been searching for hours trying to find a solution.

Need advice on table relations

I have a table Users:
[UserId] [int] IDENTITY(1,1) NOT NULL,
[UserName] [nvarchar](20) NOT NULL,
[Email] [nvarchar](100) NOT NULL,
[Password] [nvarchar](128) NOT NULL,
[PasswordSalt] [nvarchar](128) NOT NULL,
[Comments] [nvarchar](256) NULL,
[CreatedDate] [datetime] NOT NULL,
[LastModifiedDate] [datetime] NULL,
[LastLoginDate] [datetime] NOT NULL,
[LastLoginIp] [nvarchar](40) NULL,
[IsActivated] [bit] NOT NULL,
[IsLockedOut] [bit] NOT NULL,
[LastLockedOutDate] [datetime] NOT NULL,
[LastLockedOutReason] [nvarchar](256) NULL,
[NewPasswordKey] [nvarchar](128) NULL,
[NewPasswordRequested] [datetime] NULL,
[NewEmail] [nvarchar](100) NULL,
[NewEmailKey] [nvarchar](128) NULL,
[NewEmailRequested] [datetime] NULL
This table has 1 to 1 relation to Profiles:
[UserId] [int] NOT NULL,
[FirstName] [nvarchar](25) NULL,
[LastName] [nvarchar](25) NULL,
[Sex] [bit] NULL,
[BirthDay] [smalldatetime] NULL,
[MartialStatus] [int] NULL
I need to connect user to the all other tables in database so is it better to:
1) Make relations from Users - to other tables?
2) Make relations from Profiles - to other tables?
Since the table [Users] contains the Identity value and is therefore where the [UserID] value originates, I would create all the foreign keys back to it. From a performance standpoint, assuming you have your clustered index on both tables set on the [UserID] column there should be very little performance impact.
Technically I suppose the [Users] table could contain more data per row and therefore the index could span more pages and you could have milliseconds difference in lookups, but I think it makes more sense to relate it back to the table that created the [UserID] and is similarly named. That said, you can really do either.
If the PK of Profiles is a FK to Users, I would maintain consistency and use Users as the parent table in other relationships across the database.
However, if it is a true one-to-one and not a one-to-zero or one relationship, it doesn't matter.
Another consideration is how the data in this database is accessed by any applications. Do the applications use an OR/M like Entity Framework which is aware of FK relationships? If so, consider using whichever table has columns which will most commonly be accessed by queries based on the child tables. For example, an application might display Profiles.LastName and Profiles.FirstName all over the place and very rarely read anything from the Users table. In this situation, you will save your database some I/O and save your developers some keystrokes by building relationships off the Profiles table.

Resources