Table cell to count rows in other table - sql

I'm not entirely sure if I'm even going about this in the right manner.
MVC+EF site so i could do this in the controller but I would prefer it in the DB if possible.
I have two tables. One contains entries and one contains a list of members. I want the list of members to have a column that contains the count of how many times the member name appears in the list of entries. Can I do this in the definition of the table itself?
I know this query works:
select count(*)
from dbo.Entries
where dbo.Entries.AssignedTo = 'Bob Smith'
But is there any way of doing this? What is the correct syntax?
CREATE TABLE [dbo].[Members] (
[ID] INT IDENTITY (1, 1) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[Email] NVARCHAR (500) NOT NULL,
[Count] INT = select count(*) from dbo.Entries where dbo.Entries.AssignedTo = [Name]
PRIMARY KEY CLUSTERED ([ID] ASC)
I've done some searching and have tried a few different syntax's but I'm completely lost at this point so if anyone can get me headed in the correct direction I would really appreciate it.
Thanks in advance.

You could create Members as a view combining both the Entries data and another table. (Warning: Syntax not tested)
CREATE TABLE [_member_data] (
[ID] INT IDENTITY(1, 1) NOT NULL,
[Name] NVARCHAR (100) NOT NULL,
[Email] NVARCHAR (500) NOT NULL,
PRIMARY KEY CLUSTERED ([ID] ASC)
);
CREATE VIEW [dbo].[Members] AS
SELECT ID, Name, Email, COUNT(*)
FROM _member_data JOIN dbo.Entries ON [Name] = [AssignedTo]
GROUP BY 1, 2, 3;
It is possible to take this even further with triggers/rules that rewrite attempted inserts into Members as inserts to the appropriate backing table. But to get the kind of expressive information that you are looking for, you really want to explore using a view.

Related

In a SELECT command, how do I use data from one table to specify data in another?

I have 2 tables. What is important is the PlayerId and the Username.
CREATE TABLE [dbo].[Run]
(
[RunId] INT NOT NULL,
[PlayerId] INT NOT NULL,
[Duration] TIME(7) NOT NULL,
[DateUploaded] NCHAR(10) NOT NULL,
[VersionId] INT NOT NULL,
PRIMARY KEY CLUSTERED ([RunId] ASC),
CONSTRAINT [FK_Run_Player]
FOREIGN KEY ([PlayerId]) REFERENCES [dbo].[Player] ([PlayerId]),
CONSTRAINT [FK_Run_Version]
FOREIGN KEY ([VersionId]) REFERENCES [dbo].[Version] ([VersionId])
);
CREATE TABLE [dbo].[Player]
(
[PlayerId] INT NOT NULL,
[Username] NCHAR(20) NOT NULL,
[ProfilePicture] IMAGE NULL,
[Country] NCHAR(20) NOT NULL,
[LeagueId] INT NULL,
[DateJoined] DATE NULL,
PRIMARY KEY CLUSTERED ([PlayerId] ASC),
CONSTRAINT [FK_Player_League]
FOREIGN KEY ([LeagueId]) REFERENCES [dbo].[League] ([LeagueId])
);
I have a select command:
SELECT
PlayerId, Duration, VersionId, DateUploaded
FROM
[Run]
(with apologies in advance for my messy made up pseudocode), what I need it to do is:
SELECT (Player.PlayerId.Username)
What I basically need it to do, is instead of giving me just PlayerId, I need it to get the corresponding Username (from the other table) that matches each PlayerId (PlayerId is a foreign key)
So say for example instead of returning
1, 2, 3, 4, 5
it should return
John12, Abby2003, amy_932, asha7494, luke_ww
assuming, for example, Abby2003's PlayerId was 2.
I've done trial and error and either nobody's tried this before or I'm searching the wrong keywords. This is using VS 2022, ASP.NET Web Forms, and Visual Basic, but that shouldn't affect anything I don't think. Any syntax ideas or help would be greatly appreciated.
try this for join the 2 Table togother
SELECT R.RunId
,R.PlayerId
,R.Duration
,R.DateUploaded
,R.VersionId
,P.Username
,P.ProfilePicture
,P.Country
,P.LeagueId
,P.DateJoined
FROM Run R
inner join Player P on R.PlayerId = P.PlayerId
Usually in this case joins are used. You can join the two tables together, give them aliases (or don't, personal preference really), then select what you need. In this case, you would probably want an inner join. Your query would probably look something like this:
SELECT p.Username FROM [Run] r
INNER JOIN [Player] p ON r.PlayerId = p.PlayerId
Then if you need to you can put a WHERE clause after that.
More about joins here

How do I create data during a SELECT statement while doing an INSERT INTO?

Sorry if the question is confusing, but I wasn't sure how exactly to ask it. Basically I have a giant table with 20 columns and millions of rows. I want to insert into another table a subset of those rows and columns, and then also for each of those rows, create a new time and new GUID in the table. For example, let's say I have the following table:
CREATE TABLE [dbo].[AddressData](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[AddressDataGUID] [uniqueidentifier] ROWGUIDCOL NOT NULL,
[City] [varchar](32) NOT NULL,
[State] [varchar](2) NOT NULL,
[DateModified] [datetime2](7) NOT NULL,
[TS] [timestamp] NOT NULL,
CONSTRAINT [PK_AddressData_ID] PRIMARY KEY CLUSTERED [ID]
Now I also have another table that has City and State, but then it has a bunch of other columns too, like Street, Zip, etc. I want to select every distinct pair of City and State from the bigger table and stick them in the new table, and I also want it to set the DateModified to the current time, and create a new random GUID for each of those distinct pairs. I can't figure out how to do this in sql server. I tried things like the following:
INSERT INTO Community (CommunityGUID, City, [State], DateModified)
VALUES (NEWID(), t.City, t.[State], SYSUTCDATETIME())
SELECT DISTINCT City, [State] FROM FullTable t
However, I can't figure out the correct syntax. I COULD probably take care of this by creating a temp table with all nullable fields, select distinct with those two columns, and then loop through it row by row creating all of these values, and then finally selecting the fully constructed table into the other one. I'm almost tempted to do that, because that's my first instinct as a software developer and not a database developer, but DB developers tend to dislike having stuff like that in DB if there's a way to just do it in one statement and let the DB engine optimize it.
I think you just want a real query for the INSERT:
INSERT INTO Community (CommunityGUID, City, [State], DateModified)
SELECT NEWID(), t.City, t.[State], SYSUTCDATETIME()
FROM (SELECT DISTINCT City, [State]
FROM FullTable t
) t;

Computed column at creation of table gets evaluated every time

I have the following script that creates a table:
CREATE TABLE [dbo].[Persons]
(
[Id] INT IDENTITY(1,1) NOT NULL,
[Name] NVARCHAR(250) NOT NULL,
[Surname] NVARCHAR(250) NOT NULL,
[NumberOfNotes] INT NOT NULL,
[TotalCash] FLOAT NOT NULL,
[Result] AS ([NumberOfNotes] * [TotalCash] * ROUND(RAND() * 2, 0)),
CONSTRAINT [PK_Persons] PRIMARY KEY ([Id] ASC)
);
The table gets created correctly and whenever I insert a new person the Result gets calculated. Problem is that it gets re-evaluated every time I do a select. I would like the computed value to stay the same for that record. How do I achieve this? Thanks in advance!
I simple trick is to seed rand():
[Result] AS ([NumberOfNotes] * [TotalCash] * ROUND(RAND(id) * 2, 0)),
Basically, this is using a "deterministic" random number generator. You can do that in other ways as well.
Alternatively, you could just assign it a value when you insert new rows into the table.

Subqueries are not allowed in this context. Only scalar expressions are allowed in CREATE TABLE with AS syntax

I am trying to run the below script but I keep getting the error messages
"Subqueries are not allowed in this context. Only scalar expressions are allowed." on lines 16 and 34.
I know where it's failing - it is failing on the AS clauses, but I don't know how to correct it with different code to stop the errors from appearing.
I have tried looking around at other existing questions but none helped me that I can find. As the issue I have here is using data from columns in different tables along with columns in the current table.
Could I get some help with getting this working and advise what code will be better please?
Thanks for your help in advance!
Dan
This is the code for my database::
CREATE DATABASE [LEARNING]
GO
CREATE TABLE Trainees
(
Trainee_ID int IDENTITY(1,1) PRIMARY KEY NOT NULL,
Name varchar(50) NOT NULL,
[Assigned Tutor_ID] int NOT NULL,
)
GO
CREATE TABLE Tutors
(
Tutor_ID int IDENTITY(1,1) PRIMARY KEY NOT NULL,
Name varchar(50) NOT NULL,
[Assigned Trainee_ID] AS (Select Trainee_ID from Trainees where Tutors.[Assigned Trainee_ID] = Trainees.Trainee_ID) NOT NULL
)
GO
CREATE TABLE [Rooms]
(
Room_ID int IDENTITY(1,1) PRIMARY KEY NOT NULL,
[Room Name] varchar(50) NOT NULL,
[Cost per hour] money NOT NULL
)
GO
CREATE TABLE [Rooms Rented]
(
Rented_ID int IDENTITY(1,1) PRIMARY KEY NOT NULL,
Room_ID int NOT NULL,
Tutor_ID int NOT NULL,
[Length of time in hours] int NOT NULL,
[Total Cost] AS (select ([Rooms Rented].[Length of time in hours])*([Rooms].[Cost per hour]) from [Rooms]) NOT NULL
)
GO
INSERT INTO Tutors values ('Nikki Smith',1)
GO
INSERT INTO Trainees Values ('Tyler Hatherall')
GO
INSERT INTO Rooms values ('Training Room 1',6.50)
GO
INSERT INTO [Rooms Rented] values (1,1,2)
GO
Computed columns are used to ensure columns persisted property within the table itself.
In your case, you need to have another update after you created table, populate the column by the query similar to below query, also, you need to create Foreign Key in the Total Cost column based on what you try to achieve.
UPDATE A
SET A.[Total Cost] = A.[Length of time in hours] * B.[Cost per hour] --add ISNULL to treat NULL if needed
FROM [Rooms Rented] as A
INNER JOIN [Rooms] as B
ON B.Room_ID = A.Room_ID
Your AS statements are computed columns. When your computed columns refer to other tables, you cannot implement this directly. You will have to create scalar functions first.
For example, after creating Rooms, create this function that takes a room id and returns cost per hour:
create function f_get_Rooms_CostPerHour (#Room_ID int)
returns money
as
return (select [Cost per hour] from [Rooms] where [Rooms].Room_ID=#Room_ID)
Now you can use this in your computed column formula. Note that a computed column formula never has a SELECT in it. It also does not have a null/not null specification.
CREATE TABLE [Rooms Rented]
(
Rented_ID int IDENTITY(1,1) PRIMARY KEY NOT NULL,
Room_ID int NOT NULL,
Tutor_ID int NOT NULL,
[Length of time in hours] int NOT NULL,
[Total Cost] AS ([Length of time in hours]*f_get_Rooms_CostPerHour([Room_ID]))
)

How to update 2nd table with identity value of inserted rows into 1st table

I have the following table structures
CREATE TABLE [dbo].[WorkItem](
[WorkItemId] [int] IDENTITY(1,1) NOT NULL,
[WorkItemTypeId] [int] NOT NULL,
[ActionDate] [datetime] NOT NULL,
[WorkItemStatusId] [int] NOT NULL,
[ClosedDate] [datetime] NULL,
)
CREATE TABLE [dbo].[RequirementWorkItem](
[WorkItemId] [int] NOT NULL,
[RequirementId] [int] NOT NULL,
)
CREATE TABLE #RequirmentWorkItems
(
RequirementId int,
WorkItemTypeId int,
WorkItemStatusId int,
ActionDate datetime
)
I use the #RequirmentWorkItems table to create workitems for requirements. I then need to INSERT the workitems into the WorkItem table and use the identity values from the WorkItem table to create the cross-reference rows in the RequirementWorkItem table.
Is there a way to do this without cursoring thru each row? And I can't put the RequirementId into the WorkItem table because depending on the WorkItemTypeId the WorkItem could be linked to a Requirement or a Notice or an Event.
So there are really 3 xref tables for WorkItems. Or would it be better to put a RequirementId, NoticeId and EventId in the WorkItem table and 1 of the columns would have a value and other 2 would be null? Hopefully all this makes sense. Thanks.
You should read MERGE and OUTPUT – the swiss army knife of T-SQL for more information about this.
Today I stumbled upon a different use for it, returning values using an OUTPUT clause from a table used as the source of data for an insertion. In other words, if I’m inserting from [tableA] into [tableB] then I may want some values from [tableA] after the fact, particularly if [tableB] has an identity. Observe my first attempt using a straight insertion where I am trying to get a field from #source.[id] that is not used in the insertion: