I have the same table in two databases (dbSource and dbTarget) and I'm trying to write a query to compare the field values in each table with a Source/Target diff.
This is the table structure:
CREATE TABLE [dbo].[tblWidget](
[ID] [int] NOT NULL,
[Description] [varchar](50) NOT NULL,
[UpdatedBy] [varchar](50) NOT NULL,
CONSTRAINT [PK_tblWidget] PRIMARY KEY CLUSTERED
(
[ID] 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
For simplicity, I'll say the table in each database has one row:
[dbSource]:
[dbTarget]:
I want the result to look like this:
The closest I could get to the result is a PIVOT query that only returns one of the fields (UpdatedBy).
Is there a simple way to include all of the fields in one query vs. doing some kind of UNION with multiple PIVOT statements?
I realize if there is more than one row (example: a row with ID = 2), the expected results won't make sense, so please assume I will only be comparing one row between databases.
This is what I have so far:
SELECT 'UpdatedBy' Field, [0] AS [Source], [1] AS [Target]
FROM
(
SELECT [ID]
,[Description]
,[UpdatedBy]
,1 IsSource
FROM [dbSource].[dbo].[tblWidget]
UNION ALL
SELECT [ID]
,[Description]
,[UpdatedBy]
,0 IsSource
FROM [dbTarget].[dbo].[tblWidget]
) a
PIVOT (
MAX(UpdatedBy)
FOR IsSource IN ([0], [1])
) AS pvt
Thanks
You could join the two tables, and then unpivot the columns to rows:
select s.id, x.*
from dbsource.tblWidget s
inner join dbtarget.tblWidget t on t.id = s.id
cross apply (values
('Description', s.description, t.description),
('UpdatedBy', s.updatedby, t.updatedby)
) x (field, source, target)
This assumes that column id can be used to relate the two tables - as a consequence, it does not make sense having a row for id in the result (both the source and target values always are the same).
Related
I have an existing table I have created and I would like to alter my table by creating a new calculated column which will obtain the max date by ID.
Multiple times a day, new data will flow into the table from a form input (web app). Every time the ID and datestamp are entered into the database, I would like the calculated column to update.
I created my table to interact with Powerapps web form:
CREATE TABLE [dbo].[test_table2](
[Id] [int] IDENTITY(1,1) NOT NULL,
[datestamp] [date] NULL,
CONSTRAINT [tableId] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
) ON [PRIMARY]
GO
I have tried to create a column with something like this.....
SELECT id, datestamp FROM (
SELECT id, datestamp,
RANK() OVER (PARTITION BY id ORDER BY datestamp DESC) max_date_id
FROM test_table2
) where max_date_id = 1
I ultimately would like to alter the table so it updates automatically, but this code is just a query and also does not work. How can I achieve this?
A policy have a set of insuranceTypes in PolicyCoverage.
A policy have a set of insuranceTypes for a specific organization in PolicyPermissionInsuranceType.
I'm trying to get the policies that have all the insurance types form PolicyCoverage in PolicyPermissionInsuranceType for a specific organization, user and permission.
In C# I evaluate the rule (for a single policy when found for an organization) as:
public class ReadPolicyLimitedPermission
{
private IEnumerable<Guid> InsuranceTypeIds { get; }
public bool Validate(Policy entity)
{
return !entity.InsuranceTypes.Except(InsuranceTypeIds).Any();
}
}
I'm trying to write a query equal to that rule for all policies in the database. The query I have looks as follow, but is really slow when supplied with a userId that does not have a record in the table.
So the question is, is there a better way to perform this type of check?
Query:
declare #UserId uniqueidentifier = newId() --Does not exist
declare #Permission nvarchar(150) = 'ReadPolicyLimitedPermission'
select p.Id
from test.Policy p
where
not exists
(
select
pc.insuranceTypeId
from
test.PolicyCoverage pc
where
pc.PolicyId = p.Id
except
select
ppit.InsuranceType
from
test.PolicyPermissionInsuranceType ppit
where
ppit.UserId = #UserId and
ppit.Permission = #Permission and
ppit.OrganizationId = p.OrganizationId
)
Table sizes:
Policy 201762 rows
PolicyCoverage 393004 rows
PolicyPermissionInsuranceType 36984 rows
Execution plan:
Table structure:
CREATE TABLE [test].[Policy](
[Id] [uniqueidentifier] NOT NULL,
[OrganizationId] [uniqueidentifier] NOT NULL,
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]
CREATE TABLE [test].[PolicyCoverage](
[PolicyId] [uniqueidentifier] NOT NULL,
[InsuranceTypeId] [uniqueidentifier] NOT NULL
) ON [PRIMARY]
CREATE TABLE [test].[PolicyPermissionInsuranceType](
[UserId] [uniqueidentifier] NOT NULL,
[OrganizationId] [uniqueidentifier] NOT NULL,
[Permission] [nvarchar](50) NOT NULL,
[InsuranceType] [uniqueidentifier] NOT NULL,
CONSTRAINT [PK_PolicyPermissionInsuranceType] PRIMARY KEY CLUSTERED
(
[UserId] ASC,
[OrganizationId] ASC,
[Permission] ASC,
[InsuranceType] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
Or is it possible to store the data in a different way for table PolicyPermissionInsuranceType
Example:
Policy 1
-Org 1
-Type 1
-Type 2
Policy 2
-Org 1
-Type 1
-Type 3
PolicyPermission 1
-Org1
-Type1
-Type2
-Type5
The they query should return Policy1 since it has all the types in the policyPermission table (Type1, Type2) but not Policy2 since it has Type3 which the PolicyPermission1 does not have.
what if you try this:
select a.id from (
select p.id,ppt.userid From test.Policy p
join test.PolicyCoverage pc on pc.policyid = p.id
left join test.PolicyPermissionInsuranceType ppt on ppt.InsuranceType = pc.insurancetypeid
and ppt.OrganizationId = p.OrganizationId
and ppt.UserId = #UserId
and ppt.Permission = #Permission
)a
group by a.id
having COUNT(a.id) = COUNT(a.userid)
I'm posting this as an answer as I wanted to add some code you could test, so didn't seem suited to a comment. Will happily delete unless you find it useful.
You could look to create the second table in your subquery in advance as a temp table and then reference that in the subquery, which might speed things up:
declare #UserId uniqueidentifier = newId() --Does not exist
declare #Permission nvarchar(150) = 'ReadPolicyLimitedPermission'
-- temp table here
select ppit.InsuranceType, ppit.OrganizationId
into #temp
from test.PolicyPermissionInsuranceType ppit
where ppit.UserId = #UserId and
ppit.Permission = #Permission
-- original modified query with temp table
select p.Id
from test.Policy p
where
not exists
(
select pc.insuranceTypeId
from test.PolicyCoverage pc
where pc.PolicyId = p.Id
except
select ppit.InsuranceType
from #temp ppit
where ppit.OrganizationId = p.OrganizationId
)
I'm trying to write a query that checks to see , for each 'group' in a GROUP BY or PARTITIONS BY, it contains a value.
/\___ Not a very good way to describe my problem :(
So, I'll give a fake scenario which I just thought up (but it does sound like homework :( even though it's not)
Problem
List all the Cages and return a True or False if the cage has .. say ... a pug dog.
Scenario
This is a Pet Shop that sells animals.
The shop has a number of cages. Each cage has an unique number. Cage #1, #2, etc.
Some cages are empty.
The animals in the cages are either Dogs, Cats or Velociraptor's (whoa! That escalated quickly!!).
.
CageID | HasAPugDog
-------------------
1 | False
2 | True
....
I wish SqlFiddle was working (it's not) .. so here's a sample schema I quickly whipped up.
CREATE TABLE [dbo].[Cages](
[CageId] [int] IDENTITY(1,1) NOT NULL,
[MaxSize] [int] NOT NULL,
CONSTRAINT [PK_Cages] PRIMARY KEY CLUSTERED
(
[CageId] 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].[Pets](
[PetId] [int] IDENTITY(1,1) NOT NULL,
[Type] [varchar](50) NOT NULL,
[Breed] [varchar](50) NOT NULL,
[CageId] [int] NOT NULL,
CONSTRAINT [PK_Pets] PRIMARY KEY CLUSTERED
(
[PetId] 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].[Pets] WITH CHECK ADD CONSTRAINT [FK_Pets_Cages] FOREIGN KEY([CageId])
REFERENCES [dbo].[Cages] ([CageId])
GO
ALTER TABLE [dbo].[Pets] CHECK CONSTRAINT [FK_Pets_Cages]
GO
Is the trick to use a HAVING statement with a PARTITION ON ?
SIDE NOTE: When the lights go out, the security camera has recorded a Cat-wearing-ninja-clothes riding a Velociraptor around the shop.
You can use a left join, like this:
SELECT c.CageID
, CASE WHEN p.CageID IS NULL THEN 'False' ELSE 'True' END as HasAPugDog
FROM Cages c
LEFT JOIN (SELECT DISTINCT CageID
FROM Pets
WHERE Type = 'dog' And Breed = 'pug') p
You can also use an EXISTS with a correlated sub-query, but you would get less points for this solutions, as the correlated sub-queries are considered worse in terms of performance:
SELECT c.CageID
, CASE WHEN EXISTS(SELECT 1 FROM Pets p
WHERE p.CageID = c.CageID and Type = 'dog' And Breed = 'pug')
THEN 'True' ELSE 'False' END as HasAPugDog
FROM Cages c
If you would like to get the overview per Breed as a table you could use the code below.
SELECT * FROM
(select occupied = CASE WHEN p.CageId = c.CageId THEN 'TRUE' ELSE 'FALSE' END
--, p.Type
, p.Breed
--, p.CageId
, c.CageId
from Cages c
cross join Pets p) AS SourceTable
PIVOT
(
max(occupied) FOR Breed IN ([Pug], [Persian], [Velociraptor Nublarensis])
) AS PivotTable;
Resulting in the following table.
Have two tables
CREATE TABLE [dbo].[TABELAA]
(
[ID] [bigint] NOT NULL,
[PodatakA] [nvarchar](50) NULL,
[PodatakB] [nvarchar](50) NULL,
CONSTRAINT [PK_TABELAA]
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]
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TABELAB]
(
[PodatakX] [nvarchar](50) NULL,
[PodatakY] [nvarchar](50) NULL
) ON [PRIMARY]
GO
I need to insert value from tabelaB to tabelaA with autogenerating ID in tabelaA so I need something like this. But this would be great if there is only one row. I'm talking about thousands of rows where it should auto generate id exact like AutoIncrement (1)
Useless try where I think I should use OVER
INSERT INTO TABELAA
SELECT
(SELECT MAX(id) + 1 FROM TabelaA) AS Id, *
FROM
tabelaB
You are looking for the IDENTITY:
CREATE TABLE [dbo].[TABLAAA](
[ID] [bigint] IDENTITY(1, 1) PRIMARY KEY, -- NOT NULL is handled by PRIMARY KEY
[PodatakA] [nvarchar](50) NULL,
[PodatakB] [nvarchar](50) NULL
);
INSERT INTO TABLEAA (PodatakA, PodatakB)
SELECT PodatakA, PodatakB
FROM TABLEBB;
I agree with Rahul's comment and Gordon that if you can modify your schema it would make the most sense to add an Identity Column. However if you cannot you can still accomplish what you want using a couple of methods.
One method is get the MAX ID of TableAA and then add a ROW_NUMBER() to it like so:
INSERT INTO TableAA (ID, PodatakA, PodatakB)
SELECT
m.CurrentMaxId + ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
,b.PodatakA
,b.PodatakB
FROM
TableAB b
CROSS APPLY (
SELECT ISNULL(MAX(Id),0) as CurrentMaxId
FROM
TableAA) m
Again this would be work around the most ideal solution is to specify IDENTITY
Also this is susceptible to problems due to simultaneous writes and other scenarios in a heavy traffic DB.
Please Consider the following table :
As you can see the Name column has some repeated values with is a group like
I need to have a query so I can fetch just the first row of a group something like this:
Please take in to account that I need the fastest way because the real table is not like that and could have lots of data to be filter that way.
Thanks in advance.
this depends greatly on how you define 'the first in the group'
something like this:
select name, min(code)
from mytable
group by name
order by name
Assuming the table name is test (change to match yours), try this
CREATE TABLE [dbo].[test](
[name] [varchar](3) NULL,
[code] [varchar](5) NULL,
[RowNumber] [int] NOT NULL,
CONSTRAINT [PK_test] PRIMARY KEY CLUSTERED
(
[RowNumber] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
INSERT INTO [test] ([name],[code],[RowNumber])VALUES('A1','AED',1)
INSERT INTO [test] ([name],[code],[RowNumber])VALUES('A1','BG',2)
INSERT INTO [test] ([name],[code],[RowNumber])VALUES('A1','WS',3)
INSERT INTO [test] ([name],[code],[RowNumber])VALUES('A2','CER',4)
INSERT INTO [test] ([name],[code],[RowNumber])VALUES('A2','HJY',5)
INSERT INTO [test] ([name],[code],[RowNumber])VALUES('A5','OLP',6)
INSERT INTO [test] ([name],[code],[RowNumber])VALUES('A6','LOO',7)
INSERT INTO [test] ([name],[code],[RowNumber])VALUES('A6','AED',8)
SELECT a.*
FROM dbo.test a
INNER JOIN(SELECT name,
MIN(rownumber) AS rownumber
FROM dbo.test
GROUP BY name) b
ON a.name = b.name
AND a.rownumber = b.rownumber
ORDER BY a.name
If the RowNumber column is always going to be sequential the put an index on that column.