Joning tables after group by on one table using T SQL/ LINQ - sql-server

I have two tables:
db.EmployeeReason
db.employee
with following fields:
CREATE TABLE [dbo].[Employee_Reason](
[Id] [int] IDENTITY(1,1) NOT NULL,
[IdEmployee] [int] NOT NULL,
[IdReason] [int] NOT NULL,
[AverageServiceTime] [time](0) NULL,
[Skillset] [bit] NOT NULL,
CONSTRAINT [PK_Employee_Reason] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Employee_Reason] WITH CHECK ADD CONSTRAINT [FK_Employee_Reason_Employee] FOREIGN KEY([IdEmployee])
REFERENCES [dbo].[Employee] ([Id])
GO
where as the employee table looks like this:
CREATE TABLE [dbo].[Employee](
[Id] [int] IDENTITY(1,1) NOT NULL,
[EmployeeId] [int] NOT NULL,
[FirstName] [nvarchar](20) NOT NULL,
[LastName] [nvarchar](40) NOT NULL,
[IdLocation] [int] NOT NULL,
[IdStatus] [int] NOT NULL,
[UserId] [nvarchar](450) NOT NULL,
[IsArchived] [bit] NULL,
[IdAssignedLocation] [int] NOT NULL,
[IdQueue] [int] NOT NULL,
[IdPosition] [int] NOT NULL,
CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED ([Id] ASC) ON [PRIMARY]
) ON [PRIMARY]
I want to group employee_reason by idreason and then join with employee using Employee_Reason.idemployee and employee.id like this:
List<SelfServeReason> skillsetReasons =
from reason in db.EmployeeReason
group reason by IdReason into reasonGroup
join employee in scheduleEmployees on reasonGroup.IdEmployee equals employee.Id
select new skillsetReason
{
id = reasonGroup.Id,
description = reasonGroup.Description,
estimatedWaitTime = min(employee.NextAvailableTime) – ConvertToCST(DateTime.Now)
};
I have written it like this:
select MAX(er.Id)
from Employee_Reason er join Employee e on er.IdEmployee = e.id
group by er.IdReason
but not sure how to group employee_reasons and then join this group with idempoyee.
The linq is not correct, it is just pseudocode, if someone can suggest wha will be correct linq that is helpful as well.
Can you please suggest the solution?

If what you want is a SQL query simmilar to that linq query, then you could do:
select er.IdReason, MIN(e.NextAvailableTime) - GETDATE()
from Employee_Reason er
inner join Employee e on er.IdEmployee = e.id
group by er.IdReason
Also, the correct linq would look like this:
var now = ConvertToCST(DateTime.Now);
List<SelfServeReason> skillsetReasons = (
from employee in scheduleEmployees
join reason in db.EmployeeReason on employee.Id equals reason.IdEmployee
group employee by reason.IdReason into reasonGroup
select new SelfServeReason
{
Id = reasonGroup.Key,
EstimatedWaitTime = reasonGroup.Min(p => p.NextAvailableTime).Subtract(now),
}).ToList();
Just bear in mind that I excluded the selection of Description from the queries, as you provided no such column on any table nor is there a table like Reason with that column on it.
Also, the tables you provided have no such columns as Employee.NextAvailableTime, so I'm assuming you forgot to put them there, seeing that it on your linq query.
And least, you provided no spec for that SelfServeReason class, so I'll just go on with filling it with the columns I know your model have.
If that's not the case, please expand your question with this adjustments and I'll edit my answer.

Related

Is there an easier way to do a "Cascading Insert" in SQL Server 2016?

I inherited SQL code that I need to work on that was set up similar to the following:
CREATE TABLE [dbo].[Ni](
[FooID] [int] IDENTITY(1,1) NOT NULL,
[Bar] [nvarchar](60) NULL,
[LocationID] [int] NULL,
[Thing1] [float] NULL
CONSTRAINT [PK_Ni] PRIMARY KEY CLUSTERED
(
[FooID] ASC
);
CREATE UNIQUE NONCLUSTERED INDEX [UQ_LocationBar] ON [dbo].[Ni]
(
[LocationID] ASC,
[Bar] ASC
);
CREATE TABLE [dbo].[Ni_Two](
[ID] [int] IDENTITY(1,1) NOT NULL,
[FooID] [int] NOT NULL,
[Thing2] [int] NOT NULL,
[Thing3] [int] NOT NULL
CONSTRAINT [PK_Ni_Two] PRIMARY KEY CLUSTERED
(
[ID] ASC
);
ALTER TABLE [dbo].[Ni_Two] WITH CHECK ADD CONSTRAINT [FK_NiTwo_FooID] FOREIGN KEY([FooID])
REFERENCES [dbo].[Ni] ([FooID]);
CREATE TABLE [dbo].[KillMe](
[ID] [int] NOT NULL,
[FooID] [int] NULL,
[Thing4] [int] NOT NULL,
[Thing5] [int] NOT NULL
PRIMARY KEY CLUSTERED
(
[ID] ASC
);
ALTER TABLE [dbo].[KillMe] WITH NOCHECK ADD CONSTRAINT [FK_KillMe_FooID] FOREIGN KEY([FooID])
REFERENCES [dbo].[Ni] ([FooID]);
CREATE TABLE [dbo].[PleaseStop](
[ID] [int] NOT NULL,
[KillMeID] [int] NOT NULL,
[Thing7] [int] NOT NULL,
[Thing8] [int] NOT NULL
PRIMARY KEY CLUSTERED
(
[Id] ASC
);
ALTER TABLE [dbo].[PleaseStop] WITH CHECK ADD CONSTRAINT [FK_PleaseStop_KillMe] FOREIGN KEY([KillMeID])
REFERENCES [dbo].[KillMe] ([ID]);
At issue is that with this design is with [Ni].dbo.[Bar]. That unique constraint is put in there as a requirement. Every FooID is unique, and every Bar assigned to LocationID must be unique.
Now the requirements have changed. With each quarterly import there will be a few entries where the Bar field must be updated.
I have tried:
UPDATE dbo.[Ni]
SET Bar = Imp.Bar
, LocationID = Imp.LocationID
, Thing1 = Imp.Thing1
FROM dbo.[Ni]
INNER JOIN ImportData Imp ON [Ni].FooID = Imp.FooID
This will give me a Violation of UNIQUE KEY constraint error.
I don't want to change the schema because I don't know what other effects it will have on the code. The author of the program has since left the company . . . and here I am.
The program runs quarterly (I.E. four times a year) as part of a maintenance routine.
Can I do this without using WHILE statements? Because that's going to be a pain.
Thanks!
So either update them all in a single query, eg
CREATE TABLE [dbo].[Ni](
[FooID] [int] IDENTITY(1,1) NOT NULL,
[Bar] [nvarchar](60) NULL,
[LocationID] [int] NULL,
[Thing1] [float] NULL
CONSTRAINT [PK_Ni] PRIMARY KEY CLUSTERED
(
[FooID] ASC
)
);
CREATE UNIQUE NONCLUSTERED INDEX [UQ_LocationBar] ON [dbo].[Ni]
(
[LocationID] ASC,
[Bar] ASC
);
insert into Ni(bar) values ('a'),('b'),('c');
with newValues as
(
select * from (values (1,'c'),(3,'x')) newValues (FooId, Bar)
),
toUpdate as
(
select ni.FooId, ni.Bar, NewValues.Bar NewBar
from Ni
join NewValues
on ni.FooID = newValues.FooId
)
update toUpdate set Bar = NewBar
or disable and rebuild the unique index
begin transaction
alter index [UQ_LocationBar] on ni disable
update ni set bar = 'b' where fooid = 1
update ni set bar = 'a' where fooid = 2
alter index [UQ_LocationBar] on ni rebuild
commit transaction
Am I allowed to disable and re-enable the constraint in a stored procedure?
It requires additional permissions, of course, but there's no restriction on running DDL inside a stored procedure, and in SQL Server DDL is fully transactional, so you can commit/rollback to prevent partial updates and to prevent other sessions from seeing partial results.

Update a column when price column of other table is modified. Triggers. Nested tables. SQL Server

In my database I have about 10 tables connected in one central table (Mobile). This table (Mobile) has a column called price which is the sum of the prices of all other nested tables. I would like that when price of another table (like Battery, Camera, ...) is updated, the price of the central table (Mobile) would be updated too.
I will show the schema of central table and two more (for reducing code, other nested tables are so similar)
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[table_mobile]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NOT NULL,
[processor] [int] NOT NULL,
[memory_ram] [int] NOT NULL,
[memory_rom] [int] NOT NULL,
[operating_system] [int] NOT NULL,
[graphic] [int] NOT NULL,
[screen] [int] NOT NULL,
[battery] [int] NOT NULL,
[camera] [int] NOT NULL,
[material] [int] NOT NULL,
[extra] [int] NOT NULL,
[price] [decimal](18, 2) NOT NULL,
[created_by] [int] NOT NULL,
[created_at] [timestamp] NOT NULL,
CONSTRAINT [PK_mobiles]
PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[table_battery]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NOT NULL,
[capacity] [int] NOT NULL,
[description] [varchar](250) NOT NULL,
[image] [image] NOT NULL,
[price] [decimal](18, 2) NOT NULL,
CONSTRAINT [PK_table_battery]
PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[table_camera]
(
[id] [int] IDENTITY(1,1) NOT NULL,
[name] [varchar](50) NOT NULL,
[megapixels] [int] NOT NULL,
[description] [varchar](250) NOT NULL,
[image] [image] NOT NULL,
[price] [decimal](18, 2) NOT NULL,
CONSTRAINT [PK_table_camera]
PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
As I say, I think that my purpose should be achieve with a trigger but any other suggest is accepted.
I'll show you what I want to do by programming in C#:
table_mobile.price = table_battery.price + table_camera.price + ... + table_XXX.price
Any idea how can I achive my trouble?
Thank you.
EDIT 1:
Using SSMS... I have created this template for a Trigger:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TRIGGER <Schema_Name, sysname, Schema_Name>.<Trigger_Name, sysname, Trigger_Name>
ON <Schema_Name, sysname, Schema_Name>.<Table_Name, sysname, Table_Name>
AFTER <Data_Modification_Statements, , INSERT,DELETE,UPDATE>
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
END
GO
I have not worked with SQL Server for a while, so forgive me if there are any typos, but basically you will need to create a trigger for each of the tables linked to mobile and add the difference of the new and the old value to the price of the mobile:
create trigger PriceChange on table_battery
after update
as
BEGIN
update table_mobile
set price = table_mobile.price + i.price
from table_mobile
inner join INSERTED i
on table.mobile.id = i.id;
update table_mobile
set price = table_mobile.price - d.price
from table_mobile
inner join DELETED d
on table.mobile.id = d.id;
END
Note that we do separate updates, because the id might have changed. If the id stays the same, then you can use a single update with a difference. The code is untested, so if there are any problems, then please, let me know.
EDIT
You may also do this from application level where you trigger the updates. After any such update you can run an update for table_mobile, adding the values. The benefit would be that you can do the calculation only once if you know that several prices for the same mobiles will be changed.
EDIT2
Apparently this command should be used inside the trigger:
UPDATE [dbo].[table_mobile]
SET price = table_mobile.price + i.price - d.price
FROM [dbo].[table_mobile],
INSERTED i,
DELETED d
WHERE battery = d.id
This is an example of the view I mentioned:
create view MobileWithPriceAggregate as
select [id]
, [name]
, [processor]
, [memory_ram]
, [memory_rom]
, [operating_system]
, [graphic]
, [screen]
, [battery]
, [camera]
, [material]
, [extra]
, price = m.price+b.price+c.price
from [table_mobile] m
join [table_battery] b on b.id=m.battery
join [table_camera] c on c.id=m.camera
Note: if not all Mobiles have a camera, then you need to use left join and null handle like ISNULL(c.price,0)

SQL Server stored procedure with geolocation not returning data

I have written the following stored procedure to return data based on a lat/long and category id being passed.
I need to return a list of traders whose coverage area falls within the passed lat long (and that they cover the category being passed). So I am looking to draw a circle around the traders lat/long position, x number of meters using the radius they will operate from (this is stored in the Traders.OperatingRadius column). If the passed lat long coord is within this, then they should be included in the return list.
CREATE PROCEDURE FindTradersWithinRadiusLatLong
#LAT decimal(9,6),
#LONG decimal(9,6),
#CATEGORY int
AS
BEGIN
SET NOCOUNT ON;
DECLARE #GEO1 GEOGRAPHY;
SET #GEO1 = geography::Point(#LAT, #LONG, 4326)
SELECT
x.Id, x.Name,
x.Latitude, x.Longitude,
x.Distance, x.IsArchived
FROM
(SELECT
Traders.Id, Traders.Name,
Latitude, Longitude,
CategoryId = TraderCategories.Id,
OperatingRadius,
Traders.IsArchived,
Distance = (#geo1.STDistance(geography::Point(ISNULL(Latitude, 0), ISNULL(Longitude, 0), 4326)))
FROM
((Addresses
INNER JOIN
Traders ON Addresses.TraderId = Traders.Id)
INNER JOIN
TraderCategories ON Traders.Id = TraderCategories.TraderId)) AS x
WHERE
x.Distance <= x.OperatingRadius
AND x.CategoryId = #CATEGORY
AND (x.IsArchived = 0 OR x.IsArchived = NULL);
END
GO
TraderCategories is a linking table as follows;
Table TraderCategories
int FK TraderId
int FK CategoryId
Now I have added an address with;
latitiude - 43.590000, Longitude - -111.120000
There is also a TraderCategory Relationship for category with Id 1
I have then tried calling the stored procedure with the above and no matches are being returned.
The table definitions are as follows:
CREATE TABLE [Bemfeito].[Addresses]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Address1] [nvarchar](max) NULL,
[Address2] [nvarchar](max) NULL,
[Address3] [nvarchar](max) NULL,
[TraderId] [int] NULL,
[Latitude] [decimal](9, 6) NOT NULL,
[Longitude] [decimal](9, 6) NOT NULL,
[OperatingRadius] [real] NOT NULL DEFAULT (CONVERT([real],(0)))
CONSTRAINT [PK_Addresses]
PRIMARY KEY CLUSTERED ([Id] ASC)
)
GO
ALTER TABLE [Bemfeito].[Addresses] WITH CHECK
ADD CONSTRAINT [FK_Addresses_Traders_TraderId]
FOREIGN KEY([TraderId]) REFERENCES [Bemfeito].[Traders] ([Id])
GO
ALTER TABLE [Bemfeito].[Addresses] CHECK CONSTRAINT [FK_Addresses_Traders_TraderId]
GO
CREATE TABLE [Bemfeito].[Traders]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Email] [nvarchar](max) NULL
[Name] [nvarchar](max) NULL
CONSTRAINT [PK_Traders]
PRIMARY KEY CLUSTERED ([Id] ASC)
)
GO
CREATE TABLE [Bemfeito].[TraderCategories]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[CategoryId] [int] NULL,
[TraderId] [int] NULL,
CONSTRAINT [PK_TraderCategories]
PRIMARY KEY CLUSTERED ([Id] ASC)
)
GO
ALTER TABLE [Bemfeito].[TraderCategories] WITH CHECK
ADD CONSTRAINT [FK_TraderCategories_Categories_CategoryId]
FOREIGN KEY([CategoryId]) REFERENCES [Bemfeito].[Categories] ([Id])
GO
ALTER TABLE [Bemfeito].[TraderCategories] CHECK CONSTRAINT [FK_TraderCategories_Categories_CategoryId]
GO
ALTER TABLE [Bemfeito].[TraderCategories] WITH CHECK
ADD CONSTRAINT [FK_TraderCategories_Traders_TraderId]
FOREIGN KEY([TraderId]) REFERENCES [Bemfeito].[Traders] ([Id])
GO
ALTER TABLE [Bemfeito].[TraderCategories] CHECK CONSTRAINT [FK_TraderCategories_Traders_TraderId]
GO
and finally for completion the category
CREATE TABLE [Bemfeito].[Categories]
(
[Id] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](max) NULL,
[Value] [int] NOT NULL,
CONSTRAINT [PK_Categories]
PRIMARY KEY CLUSTERED ([Id] ASC)
)
Can anyone tell me where I am going wrong here please?
If you look at this microsoft reference here you should notice that the argument passed to STDistance is a geometry datatype while you are passing a Point datatype.
the line currently written like this
,Distance = (#geo1.STDistance(geography::Point(ISNULL(Latitude, 0), ISNULL(Longitude, 0), 4326))
should be written as follows.
,Distance = (#geo1.STDistance(geography::STGeomFromText('Point('+ISNULL(Longitude, 0)+' '+ISNULL(Latitude, 0)')',4326))

Compare two child table items with two similar parent tables from two databases

I need help creating a query to compare the Equipment in one database to Asset in another table. Here is my database setup:
CREATE DATABASE database1
GO
USE [database1]
GO
CREATE TABLE [dbo].[Application]
(
[ApplicationID] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[APP_NUMBRER] [int] NULL,
)
GO
CREATE TABLE [dbo].[Equipment]
(
[EquipID] [int] IDENTITY(1,1) NOT NULL,
[ApplicationID] [int] NULL,
[Year] [varchar](4) NULL,
[Make] [varchar](50) NULL,
[Model] [varchar](50) NULL
)
ALTER TABLE [dbo].[Equipment] WITH CHECK
ADD CONSTRAINT [FK_EQUIP_1]
FOREIGN KEY([ApplicationID]) REFERENCES [dbo].[APPLICATION] ([ApplicationID])
GO
INSERT INTO [Application]
VALUES (1), (2), (3)
INSERT INTO [Equipment]
VALUES (1, '1998', 'Equip1', 'Model1'),
(1, '1855', 'Equip2', 'Model2'),
(2, '1222', 'Equip3', 'Model4'),
(2, '1333', 'Equip4', 'Model4'),
(3, '1777', 'Equip5', 'Model5')
GO
CREATE DATABASE database2
GO
USE [database2]
GO
CREATE TABLE [dbo].[Application]
(
[APP_KEY] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[APP_DESCRIPTION] [varchar](40) NOT NULL
)
GO
CREATE TABLE [dbo].[ASSET]
(
[AS_KEY] [int] IDENTITY(1,1) NOT NULL PRIMARY KEY,
[AS_APP_FKEY] [int] NOT NULL,
[Year] [varchar](4) NULL,
[Make] [varchar](50) NULL,
[Model] [varchar](50) NULL
)
ALTER TABLE [dbo].[ASSET] WITH CHECK
ADD CONSTRAINT [FK_ASSET_1]
FOREIGN KEY([AS_APP_FKEY]) REFERENCES [dbo].[APPLICATION] ([APP_KEY])
GO
INSERT INTO [Application]
VALUES ('AppDesc1'), ('AppDesc2')
INSERT INTO [ASSET]
VALUES (1, '1998', 'Asset1', 'Db2Model1'),
(1, '1855', 'Asset2', 'Db2Model2'),
(2, '1222', 'Asset3', 'Db2Model3'),
(2, '1333', 'Asset4', 'Db2Model4')
GO
My query:
SELECT
ap1.APP_NUMBRER,
e.Year, e.Make, e.Model,
db2.APP_KEY, db2.Year, db2.Make, db2.Model
FROM
database1.dbo.Application ap1
JOIN
database1.dbo.Equipment e ON E.APPLICATIONID = ap1.APPLICATIONID
LEFT JOIN
(SELECT
APP_KEY, Year, Make, Model
FROM
[database2].dbo.APPLICATION ap2
JOIN
[database2].dbo.ASSET ON asset.AS_APP_FKEY = ap2.APP_KEY) db2 ON ap1.APP_NUMBRER = db2.APP_KEY
Result:
Expected result: my query is creating a few duplicate items that compare all of db1 equipment to db2 assets. I want a one to one comparison. I don't want items 2,3,6,7. Is this because of how the table relationships are set up.
It's because you're only joining on APP_NUMBER=APP_KEY. Add Year=Year to the JOIN and you will get your desired result.
Add YEAR in you join. It will solve your problem.
SELECT ap1.APP_NUMBRER, e.Year, e.Make, e.Model, db2.APP_KEY, db2.Year, db2.Make, db2.Model
FROM database1.dbo.Application ap1
JOIN database1.dbo.Equipment e
ON E.APPLICATIONID = ap1.APPLICATIONID
LEFT JOIN(
SELECT APP_KEY, Year, Make, Model
FROM [database2].dbo.APPLICATION ap2
JOIN [database2].dbo.ASSET
ON asset.AS_APP_FKEY = ap2.APP_KEY
) db2
ON ap1.APP_NUMBRER = db2.APP_KEY AND e.Year = db2.Year
Amend your JOIN condition like so
db2 ON ap1.APP_NUMBRER = db2.APP_KEY
AND e.Year = db2.Year

Select distinct from a table foreach value from another

I have a view that gets the status for each category for each venue.
I need to display all of the above, but only the latest in the status for each category for each venue.
A general idea could be, for each item in a shop, there is a status. So for the cucumbers, letters, and tomatoes in shop A, the status would be good good bad respectively. Same for shop B, C etc. Now these statuses can be updated at any time - but only the latest update should be displayed.
I have tried to create a view such as the following:
SELECT
dbo.vwVenues.HospitalID
, dbo.vwVenues.Hospital AS hospitalName
, dbo.tblVenueStatus.id AS statusId
, dbo.tblVenueStatusName.statusName
, dbo.tblVenueStatusCategories.categoryName
, dbo.tblVenueStatus.dateAdded AS statusDateAdded
, dbo.tblVenueStatus.loggedBy AS statusLoggedBy
, dbo.tblVenueStatusNotes.noteContent
, dbo.tblVenueStatusNotes.dateAdded AS noteDateAdded
, dbo.tblVenueStatusNotes.removed AS noteRemoved
, dbo.tblVenueStatus.resolved AS statusResolved
, dbo.tblVenueStatus.resolveDate AS statusResolveDate
, dbo.tblVenueStatus.removed AS statusRemoved
, dbo.tblVenueStatus.dateRemoved AS statusRemovedDate
, dbo.tblVenueStatus.categoryId
FROM
dbo.tblVenueStatusName
RIGHT OUTER JOIN dbo.tblVenueStatusNotes
RIGHT OUTER JOIN dbo.tblVenueStatus
ON dbo.tblVenueStatusNotes.id = dbo.tblVenueStatus.noteId
LEFT OUTER JOIN dbo.tblVenueStatusCategories
ON dbo.tblVenueStatus.categoryId = dbo.tblVenueStatusCategories.id
ON dbo.tblVenueStatusName.id = dbo.tblVenueStatus.statusNameId
FULL OUTER JOIN dbo.vwVenues
ON dbo.tblVenueStatus.venuId = dbo.vwVenues.HospitalID
I get all the venues, but I get all the statuses for each category, instead of just the latest. Even trying to phrase the question right was hard - so my current search yeilded nothing.
Could anyone please help?
Edit
CREATE TABLE [dbo].[tblVenueStatus](
[id] [int] IDENTITY(1,1) NOT NULL,
[statusNameId] [int] NOT NULL,
[venuId] [int] NOT NULL,
[categoryId] [int] NOT NULL,
[loggedBy] [nvarchar](50) NOT NULL,
[noteId] [int] NOT NULL,
[dateAdded] [datetime] NOT NULL,
[resolved] [tinyint] NOT NULL,
[resolveDate] [datetime] NULL,
[removed] [tinyint] NOT NULL,
[dateRemoved] [datetime] NULL,
CONSTRAINT [PK_tblSiteVenuStatus] PRIMARY KEY CLUSTERED
CREATE TABLE [dbo].[tblVenueStatusCategories](
[id] [int] IDENTITY(1,1) NOT NULL,
[categoryName] [nvarchar](50) NOT NULL,
[categoryDescription] [nvarchar](150) NULL,
CONSTRAINT [PK_tblVenueStatusCategories] PRIMARY KEY CLUSTERED
CREATE TABLE [dbo].[tblVenueStatusName](
[id] [int] IDENTITY(1,1) NOT NULL,
[statusName] [nvarchar](50) NOT NULL,
[statusDescription] [nchar](150) NULL,
CONSTRAINT [PK_tblVenuStatusName] PRIMARY KEY CLUSTERED
CREATE TABLE [dbo].[tblVenueStatusNotes](
[id] [int] IDENTITY(1,1) NOT NULL,
[noteContent] [nvarchar](500) NULL,
[dateAdded] [datetime] NOT NULL,
[removed] [tinyint] NOT NULL,
[dateRemoved] [datetime] NULL,
CONSTRAINT [PK_tblVenueStatusNotes] PRIMARY KEY CLUSTERED
Desired Output will be:
Venu Name | Category 1 Status | Category 2 Status
Try something like this. It's largely sumerised because of what you said you needed to see in your sample. Try this and let me know if it helps. You can add other columns you need here, It is taking the latest status in each category for each hospital, and showing all hospitals and categories in a easily readable grid.
SELECT * FROM
(
SELECT VwV.HospitalID, vwV.Hospital, ISNULL(vStatusName.statusName, '') AS statusName, vStatusCategories.categoryName
FROM
(
SELECT topStatus.HospitalID, topStatus.categoryId, sta2.id
FROM
(
SELECT HospitalID, categoryId, MAX(sta.dateAdded) AS DateAdded
FROM vwVenues
INNER JOIN tblVenueStatus sta ON sta.venuId = dbo.vwVenues.HospitalID
GROUP BY HospitalID, categoryId
) topStatus
INNER JOIN tblVenueStatus sta2 ON sta2.dateAdded = topStatus.DateAdded AND sta2.venuId = topStatus.HospitalID) Statuss
FULL OUTER JOIN vwVenues vwV ON vwV.HospitalID = Statuss.HospitalID
LEFT OUTER JOIN tblVenueStatus vStatus ON vStatus.id = Statuss.id
LEFT OUTER JOIN tblVenueStatusName vStatusName ON vStatusName.id = vStatus.statusNameId
LEFT OUTER JOIN tblVenueStatusCategories vStatusCategories ON vStatus.categoryId = vStatusCategories.id AND vStatusName.id = vStatus.statusNameId
LEFT OUTER JOIN tblVenueStatusNotes vStatusNotes ON vStatusNotes.id = vStatus.noteId
) AS s
PIVOT (MIN(StatusName)
FOR [CategoryName] IN ([Category1],[Category2])) AS PTbl

Resources