MS PowerApps: How to "Patch" a SQL Table with Composite Primary Key - sql-server

I am relatively new to MS PowerApps
I have a SQL Server Express installed on a onsite server with a Gateway for PowerApps
My SQL Server table has a composite primary key, it is defined as:
CREATE TABLE [GFX_Information].[BusinessParnterAccess]
(
[BpAccesID] [int] IDENTITY(1,1) NOT NULL,
[CreatedDate] [datetime] NOT NULL,
[UpdatedDate] [datetime] NOT NULL,
[LastOperatorID] [int] NOT NULL,
[CreateByID] [int] NOT NULL,
[BPID] [int] NOT NULL,
[AllowedOperatorID] [int] NOT NULL,
[AccessFlag] [varchar](10) NULL,
PRIMARY KEY CLUSTERED ([AllowedOperatorID] ASC, [BPID] ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF,
IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON,
ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [GFX_Information].[BusinessParnterAccess]
ADD DEFAULT (GETDATE()) FOR [CreatedDate]
GO
ALTER TABLE [GFX_Information].[BusinessParnterAccess]
ADD DEFAULT (GETDATE()) FOR [UpdatedDate]
GO
I am trying to work out how to "Patch" a new record.
Currently, using the OnVisible event I create a variable to hold the last BpAccesID like this
UpdateContext ({varLastAccessID:First(SortByColumns('[GFX_Information].[BusinessParnterAccess]',"BpAccesID",Descending)).BpAccesID});
I am using a manual set of values for the Patch Command for testing purposes. The Patch command is
Patch('[GFX_Information].[BusinessParnterAccess]',Defaults('[GFX_Information].[BusinessParnterAccess]')
,{BpAccesID:varLastAccessID+1
,CreatedDate: Now()
,UpdatedDate:Now()
,LastOperatorID:4
,CreateByID:4
,BPID:342
,AllowedOperatorID:4
,AccessFlag:"RW" });
However, this does not throw an error I can detect nor can I see what I am missing
Can any one provide any ideas please?

I was reading this, and this is a suggestion is based on my knowledge of SQL Server and a quick read about Patch. It may help you, or may not (I'm sorry). And also just confirming: I'm guessing that the question is "this doesn't create a new row and I cannot see why?"
I would guess that your issue is with BPAccessId. You've set it as an identity: [BpAccesID] [int] IDENTITY(1,1) NOT NULL,
However, you explicitly insert a value into it
Patch('[GFX_Information].[BusinessParnterAccess]',Defaults('[GFX_Information].[BusinessParnterAccess]')
,{BpAccesID:varLastAccessID+1
Of course, you usually cannot insert into an IDENTITY column in SQL Server - you need to set IDENTIY_INSERT on (then off again after you finish). Also, as an aside, one of the reasons for IDENTITY PK columns is to always create a new row with a valid PK. How does the approach above work for concurrency e.g., two users trying to create a new row at the same time?
Anyway, some potential solutions off the top of my head. Once again, this is based off my knowledge of SQL Server only.
Alter the MS Powerapps statement to work with the IDENTITY (I'll leave this up to you) - whether the equivalent of SET IDENTITY_INSERT table ON; or otherwise
Remove the IDENTITY property from BPAccessID (e.g., leave it as a pure int)
Make the Primary Key a composite of all three columns e.g., AllowedOperatorID, BPID, BPAccessID
Make BPAccessID the Primary Key but non-clustered, and make a unique clustered index for AllowedOperatorID, BPID
For the bottom two, as BPAccessID is still an IDENTITY, you'll need to let SQL Server handle calculating the new value.
If you are not using foreign keys to this table, then the bottom two will have similar effects.
However, if there are foreign keys, then the bottom one (a non-clustered PK and clustered unique index on the other two) is probably the closest to your current setup (and is actually what I would typically do in a table structure like yours, regardless of PowerApps or other processing).

Related

Why is SSMS-produced script missing indexes?

SSMS 17.4, SQL Server 2017 Developer's Edition on Win10 1709
I have installed the WorldWideImporters sample database. One of the tables, Sales.Customers, has several foreign keys AND several foreign key indexes. When scripting the table (Script Table, CREATE To…), the script includes the foreign keys, but not the foreign key indexes. If I just change the name of the table and run the generated script, the table is created with all of the FK constraints, but none of the FK indexes.
For something you can see even if you don't have the WWI sample installed, I did this.
CREATE TABLE bar (
bar_id int,
col1 varchar(20),
CONSTRAINT pk_bar PRIMARY KEY CLUSTERED (bar_id)
)
CREATE TABLE foo (
foo_id int,
foobar_id int,
col1 varchar(20),
CONSTRAINT pk_foo PRIMARY KEY CLUSTERED (foo_id)
)
ALTER TABLE foo WITH CHECK
ADD CONSTRAINT FK_bar FOREIGN KEY (foobar_id) REFERENCES bar (bar_id)
ALTER TABLE foo CHECK CONSTRAINT FK_bar
That creates two tables, with foo having a FK constraint to bar. I then scripted the table from SSMS.
CREATE TABLE [dbo].[foo](
[foo_id] [int] NOT NULL,
[foobar_id] [int] NULL,
[col1] [varchar](20) NULL,
CONSTRAINT [pk_foo] PRIMARY KEY CLUSTERED
(
[foo_id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [USERDATA]
) ON [USERDATA]
GO
ALTER TABLE [dbo].[foo] WITH CHECK ADD CONSTRAINT [FK_bar] FOREIGN KEY([foobar_id])
REFERENCES [dbo].[bar] ([bar_id])
GO
ALTER TABLE [dbo].[foo] CHECK CONSTRAINT [FK_bar]
GO
So far, so good.
But then I added an index on foo on the FK column.
CREATE NONCLUSTERED INDEX FK_bar ON foo (foobar_id)
Scripting the table then produces the exact same script as above. Thus, SSMS is producing the same script whether there's an index on the FK column or not. (I confirmed with sp_helpindex that the FK index does indeed exist.)
Is this a bug in SSMS or am I mis-understanding something?
Scripting out the index is turned off by default in SSMS. Personally, that is one of the first things I turn back on along with scripting permissions and triggers. You can find this setting by:
In SSMS, open the Tools menu and pick Options
Scroll down to SQL Server Object Explorer and expand the tree
Click on the Scripting node and change Script indexes to true

Generating script in SSMS 2016 RC for Azure database omits default values

I have migrated my local SQL Server database to Azure using the built-in migration tool in SSMS 2016 release candidate. Apart from a number of failed conversions of stored procedures which use features disallowed in Azure, it looks OK.
I have now generated scripts of the schema from both the local and the Azure versions of the database, using the same scripting options, so that I can compare the scripts of the databases and identify any differences or other missing items.
My problem is that the script generated from Azure does not include the default value constraints on columns. Looking at the table definitions directly in SSMS shows that the default values have correctly been set.
Can anyone help me to get the SSMS script generator to add the default value constraints into the generated script?
This is an example script from the local database:
SET ANSI_NULLS ON
CREATE TABLE [xOrgBusinessType](
[OrgID] [int] NOT NULL,
[BusTypeID] [int] NOT NULL,
[CRD] [datetime] NOT NULL CONSTRAINT [DF_xOrgBusinessType_CRD] DEFAULT (getutcdate()),
[CRDByID] [int] NOT NULL CONSTRAINT [DF_xOrgBusinessType_CRDByID] DEFAULT ((0)),
CONSTRAINT [PK_xOrgBusinessType] PRIMARY KEY CLUSTERED
(
[OrgID] ASC,
[BusTypeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
)
and the equivalent script from the Azure database
SET ANSI_NULLS ON
CREATE TABLE [xOrgBusinessType](
[OrgID] [int] NOT NULL,
[BusTypeID] [int] NOT NULL,
[CRD] [datetime] NOT NULL,
[CRDByID] [int] NOT NULL,
CONSTRAINT [PK_xOrgBusinessType] PRIMARY KEY CLUSTERED
(
[OrgID] ASC,
[BusTypeID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON)
)
I have found the answer to my own question. I made a mistake when comparing the scripts from the two databases. The local database script was generated by SSMS 2014, whereas the Azure database script was generated by SSMS 2016, and the two versions treat CONSTRAINT .. DEFAULT .. differently.
In the case of 2014, the constraint is scripted with the column definition. In the case of 2016, all the constraints are scripted in a later block, as ALTER TABLE .. ADD CONSTRAINT .. commands.
Although my question is answered, the SSMS 2016 approach seems somewhat bizarre. In the case of the script above, the CREATE TABLE script is around line 2500, while the ALTER TABLE script is at line 13100. Further, I had set the option to "Include descriptive headers", but the ALTER TABLE statements are not preceded by an object header, even though that part of the script defines a constraint object.
I wonder why the ALTER TABLE statements are so far removed from the table definitions. There seems to be no reason not to include them right after to the CREATE TABLE script.

Convert INT to BIGINT in SQL Server

SQL 2005, 600,000,000 rows.
I have a table called Location currently using the data type INT in identity PK column LocationID. I would like to attempt converting this data type to BIGINT.
The following script I think should help to allow inserted into the PK column but i am unsure how to progress form here.
SET IDENTITY_INSERT LOCATION ON /*allows insert into the identity column*/`
SET IDENTITY_INSERT LOCATION OFF /*Returns the identity column to initial state*/`
Location table create script below:
CREATE TABLE [dbo].[Location](
[LocationID] [int] IDENTITY(1,1) NOT NULL,
[JourneyID] [int] NULL,
[DeviceID] [int] NOT NULL,
[PacketTypeID] [int] NULL,
[PacketStatusID] [int] NULL,
CONSTRAINT [Location_PK] PRIMARY KEY CLUSTERED
(
[LocationID] 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].[Location] WITH CHECK ADD CONSTRAINT [Device_Location_FK1] FOREIGN KEY([DeviceID])
REFERENCES [dbo].[Device] ([DeviceID])
GO
ALTER TABLE [dbo].[Location] CHECK CONSTRAINT [Device_Location_FK1]
GO
ALTER TABLE [dbo].[Location] WITH CHECK ADD CONSTRAINT [PacketStatus_Location_FK1] FOREIGN KEY([PacketStatusID])
REFERENCES [dbo].[PacketStatus] ([PacketStatusID])
GO
ALTER TABLE [dbo].[Location] CHECK CONSTRAINT [PacketStatus_Location_FK1]
GO
ALTER TABLE [dbo].[Location] WITH CHECK ADD CONSTRAINT [PacketType_Location_FK1] FOREIGN KEY([PacketTypeID])
REFERENCES [dbo].[PacketType] ([PacketTypeID])
GO
ALTER TABLE [dbo].[Location] CHECK CONSTRAINT [PacketType_Location_FK1]
One option i think would be to copy the data to a new table then delete the old table and rename the new one however we have constraints that will need to be dropped for this to work.
Your idea of a new table is the way to go.
On a development server, you can see the script that SSMS would produce if you change the data type using the table designer. It is a good start. This will add triggers and constraints back afterwards.
A tool like Red gate SQL Compare also allows you to check that everything was created OK

Include not available in covering indexes in SQL Server 2008 Express

In MS SQL Server Manager Studio for 2008 Express, the "Included Columns" field is always grayed out in the "Indexes/Keys" window in the Database Diagram designer.
Per the help, this should be available so long as I'm not creating a clustered index.
Further, if I run a query to create the index (which runs fine), the created query doesn't list for the table it was added against.
I don't see anywhere where MS says this feature is unavailable in the Express version.
Any ideas?
Further data:
This is the script that creates the table:
CREATE UNIQUE INDEX IX_SocialTypes_Cover ON ClientSocialTypes(ClientID, SocialTypeID, [Source]) INCLUDE (URLID)
Here is the table gen script (the index is missing):
CREATE TABLE [dbo].[ClientSocialTypes](
[SocialTypeID] [int] IDENTITY(1,1) NOT NULL,
[ClientID] [int] NOT NULL,
[SocialTypeClassID] [tinyint] NOT NULL,
[Source] [nvarchar](50) NOT NULL,
[TagCount] [int] NOT NULL,
[URLID] [int] NULL,
CONSTRAINT [PK_ClientSources] PRIMARY KEY CLUSTERED
(
[SocialTypeID] 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].[ClientSocialTypes] WITH CHECK ADD CONSTRAINT [FK_ClientSocialTypes_Clients] FOREIGN KEY([ClientID])
REFERENCES [dbo].[Clients] ([ClientID])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[ClientSocialTypes] CHECK CONSTRAINT [FK_ClientSocialTypes_Clients]
GO
ALTER TABLE [dbo].[ClientSocialTypes] WITH CHECK ADD CONSTRAINT [FK_ClientSocialTypes_SocialTypeClasses] FOREIGN KEY([SocialTypeClassID])
REFERENCES [dbo].[SocialTypeClasses] ([SocialTypeClassID])
GO
ALTER TABLE [dbo].[ClientSocialTypes] CHECK CONSTRAINT [FK_ClientSocialTypes_SocialTypeClasses]
GO
ALTER TABLE [dbo].[ClientSocialTypes] ADD CONSTRAINT [DF_ClientSocialTypes_SocialTypeClassID] DEFAULT ((1)) FOR [SocialTypeClassID]
GO
ALTER TABLE [dbo].[ClientSocialTypes] ADD CONSTRAINT [DF_ClientSocialTypes_TagCount] DEFAULT ((0)) FOR [TagCount]
GO
ALTER TABLE [dbo].[ClientSocialTypes] ADD CONSTRAINT [DF_ClientSocialTypes_HasTrackedURL] DEFAULT ((0)) FOR [URLID]
GO
There's TWO different index dialogs. An ancient horrible awful one, and a new (only just discovered it) one that actually lets you change these things.
OLD HORRIBLE ONE
Right click on a table in your main tables list
Click 'Design'
Right click on the list of columns and select 'Indexes/Keys'
This doesn't let you change included columns.
NEW NICE ONE
Expand the table in your main tables list to show the 'Columns', 'Keys', 'Constraints', 'Triggers' etc folders
Expand the Indexes folder
Right click Indexes folder for New Index
Right click existing index and click Properties to edit an existing index
This newer dialog allows you to do a lot more and I'm kind of disappointed in Microsoft for keeping the old one alive and for how long it's taken me to discover it.
It turns out this is grayed out in the full version of SQL Server too. In SSMS, use the Object Explorer (not the Designer) to navigate to {database_name} > Tables > {table_name} > Indexes to manage indexes that have includes.
The index may actually be a unique constraint (using CREATE/ALTER TABLE) rather than an index created using CREATE INDEX. Unique constraints don't allow INCLUDEs.
It's quite confusing... generate a script for the index/key entry or table and you'll be able to confirm.
Edit:
When you create the index separately you have to refresh Object Explorer
Do you have 2 SocialType tables in different schemas? (eg dbo.SocialType and [domain\myuser].SocialType). This can happen if you don't specify the schema in DDL statements.

DB advice needed for performance of a 'SessionVisit' table

I have a 'SessionVisit' table which collects data about user visits.
The script for this table is below. There may be 25,000 rows added a day.
The table CREATE statement is below. My database knowledge is definitely not up to scratch as far as understanding the implications of such a schema.
Can anyone give me their 2c of advice on some of these issues :
Do I need to worry about ROWSIZE for this schema for SQL Server 2008. I'm not even sure how the 8kb rowsize works in 2008. I don't even know if I'm wasting a lot of space if I'm not using all 8kb?
How should I purge old records I don't want. Will new rows fill in the empty spaces from dropped rows?
Any advice on indexes
I know this is quite general in nature. Any 'obvious' or non obvious info would be appreciated.
Here's the table :
USE [MyDatabase]
GO
/****** Object: Table [dbo].[SessionVisit] Script Date: 06/06/2009 16:55:05 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[SessionVisit](
[SessionGUID] [uniqueidentifier] NOT NULL,
[SessionVisitId] [int] IDENTITY(1,1) NOT NULL,
[timestamp] [timestamp] NOT NULL,
[SessionDate] [datetime] NOT NULL CONSTRAINT [DF_SessionVisit_SessionDate] DEFAULT (getdate()),
[UserGUID] [uniqueidentifier] NOT NULL,
[CumulativeVisitCount] [int] NOT NULL CONSTRAINT [DF_SessionVisit_CumulativeVisitCount] DEFAULT ((0)),
[SiteUserId] [int] NULL,
[FullEntryURL] [varchar](255) NULL,
[SiteCanonicalURL] [varchar](100) NULL,
[StoreCanonicalURL] [varchar](100) NULL,
[CampaignId] [int] NULL,
[CampaignKey] [varchar](50) NULL,
[AdKeyword] [varchar](50) NULL,
[PartnerABVersion] [varchar](10) NULL,
[ABVersion] [varchar](10) NULL,
[UserAgent] [varchar](255) NULL,
[Referer] [varchar](255) NULL,
[KnownRefererId] [int] NULL,
[HostAddress] [varchar](20) NULL,
[HostName] [varchar](100) NULL,
[Language] [varchar](50) NULL,
[SessionLog] [xml] NULL,
[OrderDate] [datetime] NULL,
[OrderId] [varchar](50) NULL,
[utmcc] [varchar](1024) NULL,
[TestSession] [bit] NOT NULL CONSTRAINT [DF_SessionVisit_TestSession] DEFAULT ((0)),
[Bot] [bit] NULL,
CONSTRAINT [PK_SessionVisit] PRIMARY KEY CLUSTERED
(
[SessionGUID] 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 [dbo].[SessionVisit] WITH CHECK ADD CONSTRAINT [FK_SessionVisit_KnownReferer] FOREIGN KEY([KnownRefererId])
REFERENCES [dbo].[KnownReferer] ([KnownRefererId])
GO
ALTER TABLE [dbo].[SessionVisit] CHECK CONSTRAINT [FK_SessionVisit_KnownReferer]
GO
ALTER TABLE [dbo].[SessionVisit] WITH CHECK ADD CONSTRAINT [FK_SessionVisit_SiteUser] FOREIGN KEY([SiteUserId])
REFERENCES [dbo].[SiteUser] ([SiteUserId])
GO
ALTER TABLE [dbo].[SessionVisit] CHECK CONSTRAINT [FK_SessionVisit_SiteUser]
I see SessionGUID and SessionVisitId, why have both a uniqueidentifier and an Identity(1,1) on the same table? Seems redundant to me.
I see referer and knownrefererid, think about getting the referer from the knownrefererid if possible. This will help reduce excess writes.
I see campaignkey and campaignid, again if possible get from the campaigns table if possible.
I see orderid and orderdate. I'm sure you can get the order date from the orders table, correct?
I see hostaddress and hostname, do you really need the name? Usually the hostname doesn't serve much purpose and can be easily misleading.
I see multiple dates and timestamps, is any of this duplicate?
How about that SessionLog column? I see that it's XML. Is it a lot of data, is it data you may already have in other columns? If so get rid of the XML or the duplicated columns. Using SQL 2008 you can parse data out of that XML column when reporting and possibly eliminate a few extra columns (thus writes). Are you going to be in trouble in the future when developers add more to that XML? XML to me just screams 'a lot of excessive writing'.
Mitch says to remove the primary key. Personally I would leave the index on the table. Since it is clustered that will help speed up write times as the DB will always write new rows at the end of the table on the disk.
Strip out some of this duplicate information and you'll probably do just fine writing a row each visit.
Well, I'd recommend NOT inserting a few k of data with EVERY page!
First thing I'd do would be to see how much of this information I could get from a 3rd party analytics tool, perhaps combined with log analysis. That should allow you to drop a lot of the fields.
25k inserts a days isn't much, but the catch here is that busier your site gets, the more load this is going to put on the db. Perhaps you could build a queuing system that batches the writes, but really, most of this information is already in the logs.
Agre with Chris that you would probably be better off using log analysis (check out Microsoft's free Log Parser)
Failing that, I would remove the Foreign Key constraints from your SessionVisit table.
You mentioned rowsize; the varchar's in your table do not pre-allocate to their maximum length (more 4 + 4 bytes for an empty field (approx.)). But saying that, a general rule is to keep rows as 'lean' as possible.
Also, I would remove the primary key from the SessionGUID (GUID) column. It won't help you much.
That's also an awful lot of nulls in that table. I think you should group together the columns that must be non-null at the same time. In fact, you should do a better analysis of the data you're writing, rather than lumping it all together in a single table.

Resources