SQL INSERT with INNER JOIN from list of constant strings - sql

I want to create a SQL Server 2012 Query which inserts a constant list of permission names, e.g. "ViewUsersPermission", "ModifyUsersPermission" into the table RolePermissions.
This table has two columns: A "RoleID" which is a foreign key to the Roles table, and a varchar column "PermissionTypeName".
INSERT INTO [dbo].[RolePermissions] ([PermissionTypeName], [RoleID])
SELECT 'ViewUsersPermission' AS [PermissionTypeName]
UNION ALL
SELECT 'ModifyUsersPermission' AS [PermissionTypeName]
UNION ALL
SELECT 'ViewRolesPermission' AS [PermissionTypeName]
INNER JOIN (SELECT [RoleID] FROM [dbo].[Roles]
WHERE [Name] = 'Administrator')
I am looking for a better solution. I want to specify a list of permissions types like:
SELECT FROM 'ViewUsersPermission', 'ModifyUsersPermission', 'ViewRolesPermission'
instead of using the UNION ALL construct.

Assuming you are on at least 2008
SELECT RoleName
FROM (VALUES('ViewUsersPermission'),
('ModifyUsersPermission'),
('ViewRolesPermission')) V(RoleName)

Based on the help from Martin, the complete SQL INSERT statement looks the following:
INSERT INTO [dbo].[RolePermissions] ([PermissionTypeName], [RoleID])
SELECT [PermissionTypeName], [RoleID] FROM (VALUES('ViewUsersPermission'),
('ModifyUsersPermission'), ('ViewRolesPermission')) V([PermissionTypeName])
INNER JOIN [dbo].[Roles] AS [Role]
ON [Role].[Name] = 'Administrator'

Related

Select Statement in SQL inheritance

CREATE TABLE User(
UserID int primary key,
Name varchar,
type int
);
CREATE TABLE Student(
UserID int primary key references User(UserID),
marks int
);
CREATE TABLE Lecture(
UserID int primary key references User(UserID),
salary int
);
Can someone help with with select statement for Student or lecture.
Both Lecture and Student tables are inheriting from User table,So I need to know how insert data and select data from these tables.
To query the tables, this would work:
SELECT u.[Name]
, s.marks
, l.salary
FROM [User] u
INNER JOIN Student s
ON u.UserId = s.UserId
INNER JOIN Lecture l
ON u.UserId = l.UserId;
However, if there are no records in the Student / Lecture tables yet, you should use LEFT Join instead.
As for inserting the data, you would need to use SCOPE_IDENTITY().
Insert into [User] (Name) values ('Melvin')
Get the identity of the UserId
DECLARE #userId INT;
SELECT #userId = SCOPE_IDENTITY ();
INSERT INTO Student
(
UserID
, Marks
)
VALUES
(userId, 5);
Update: Just noticed this was SQL Lite, which I'm not so familiar with, but it looks like it supports last_insert_rowid() instead of SCOPE_IDENTITY (), but you should get the gist of it.
If you want to select Student X:
SELECT *
FROM Student
WHERE UserID = X
If you want to select all Students and their User data, you'll want something like:
SELECT *
FROM User
JOIN Student ON User.UserID = Student.UserID
I don't understand your question but I think you need something like that
select Name, marks
from User as u, Student as s
inner join u.UserID == s.UserID;

How to select from a master table but replace certain rows using a secondary, linked table?

I have two tables with a foreign key relationship on an ID. I'll refer to them as master and secondary to make things easier and also not worry about the FK for now. Here is cut down, easy to reproduce example using table variables to represent the problem:
DECLARE #Master TABLE (
[MasterID] Uniqueidentifier NOT NULL
,[Description] NVARCHAR(50)
)
DECLARE #Secondary TABLE (
[SecondaryID] Uniqueidentifier NOT NULL
,[MasterID] Uniqueidentifier NOT NULL
,[OtherInfo] NVARCHAR(50)
)
INSERT INTO #Master ([MasterID], [Description])
VALUES ('0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3', 'Test')
,('2696ECD2-FFDB-4E26-83D0-F146ED419C9C', 'Test 2')
,('F21568F0-59C5-4950-B936-AA73DA6009B5', 'Test 3')
INSERT INTO #Secondary (SecondaryID, MasterID, Otherinfo)
VALUES ('514673A6-8B5C-429B-905F-15BD8B55CB5D','0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3','Other info')
SELECT [MasterID], [Description], NULL AS [OtherInfo] FROM #Master
UNION
SELECT S.[MasterID], M.[Description], [OtherInfo] FROM #Secondary S
JOIN #Master M ON M.MasterID = S.MasterID
With the results.....
0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3 Test NULL
0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3 Test Other info
F21568F0-59C5-4950-B936-AA73DA6009B5 Test 3 NULL
2696ECD2-FFDB-4E26-83D0-F146ED419C9C Test 2 NULL
.... I would like to only return records from #Secondary if there is a duplicate MasterID, so this is my expected output:
0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3 Test Other info
F21568F0-59C5-4950-B936-AA73DA6009B5 Test 3 NULL
2696ECD2-FFDB-4E26-83D0-F146ED419C9C Test 2 NULL
I tried inserting my union query into a temporary table, then using a CTE with the partition function. This kind of works but unfortunately returns the row from the #Master table rather than the #Secondary table (regardless of the order I select). See below.
DECLARE #Results TABLE (MasterID UNIQUEIDENTIFIER,[Description] NVARCHAR(50),OtherInfo NVARCHAR(50))
INSERT INTO #Results
SELECT [MasterID], [Description], NULL AS [OtherInfo] FROM #Master
UNION
SELECT S.[MasterID], M.[Description], [OtherInfo] FROM #Secondary S
JOIN #Master M ON M.MasterID = S.MasterID
;WITH CTE AS (
SELECT *, RN= ROW_NUMBER() OVER (PARTITION BY [MasterID] ORDER BY [Description] DESC) FROM #Results
)
SELECT * FROM CTE WHERE RN =1
Results:
0C1F1A0C-1DB5-4FA2-BC70-26AA9B10D5C3 Test NULL 1
F21568F0-59C5-4950-B936-AA73DA6009B5 Test 3 NULL 1
2696ECD2-FFDB-4E26-83D0-F146ED419C9C Test 2 NULL 1
Note that I am not just trying to select the rows which have a value for OtherInfo, this is just to help differentiate the two tables in the result set.
Just to reiterate, what I need to only return the rows present in #Secondary, when there is a duplicate MasterID. If #Secondary has a row for a particular MasterID, I don't need the row from #Master. I hope this makes sense.
What is the best way to do this? I am happy to redesign my database structure. I'm effectively trying to have a master list of items but sometimes take one of those and assign extra info to it + tie it to another ID. In this instance, that record replaces the master list.
You are way overcomplicating this. All you need is a left join.
SELECT M.[MasterID], M.[Description], S.[OtherInfo] FROM #Master M
LEFT JOIN #Secondary S ON M.MasterID = S.MasterID
Union seems to be the wrong approach... I would suggest a left join:
SELECT m.[MasterID], m.[Description], s.[OtherInfo]
FROM #Master m
LEFT JOIN #Secondary s ON s.MasterID = m.MasterID

Associative table in SQL Server

If I have 4 tables (Army, Navy, Air Force, Marines), all have serial number as primary key, and name. And I have a table operation which has op_num as primary key and op_name. I also have a table operation member, which associates the operation table to other 4 tables, how can I write a single SQL statement, return the names of the members (regardless of branch of service) of the covert operation 'Desert Storm' using Microsoft T-SQL syntax?
Given that your association table looks like this
Operation_Member (op_num, ser_num)
the following query should return the desired result:
SELECT Soldier.Name FROM Operation_Member
INNER JOIN Operation
ON Operation.op_num = Operation_Member.op_num
INNER JOIN
(
SELECT ser_num, name FROM Army
UNION ALL
SELECT ser_num, name FROM Navy
UNION ALL
SELECT ser_num, name FROM Air_Force
UNION ALL
SELECT ser_num, name FROM Marines
) Soldier
ON Soldier.ser_num = Operation_Member.ser_num
WHERE Operation.op_name = 'Desert Storm'

Join query on comma separated values

This is my 1st table :
this is another table on which i want to perform join operation :
I want to retrieve first_name for "activity_cc" column
For example, I want to show Pritam,Niket for activity_id=2
How can I retrieve those values?
From http://mikehillyer.com/articles/an-introduction-to-database-normalization/
The first normal form (or 1NF) requires that the values in each column
of a table are atomic. By atomic we mean that there are no sets of
values within a column.
Your database design violates the first normal form of database design. It is a simply unworkable design and it must be changed (and frankly the database designer who created this should be fired as this is gross incompetence) or there will be severe performance problems and querying will always be difficult. There is a reason why the very first rule of database design is never store more than one piece of information in a field.
Yes you could use some hack methods to get the answer you want, but they will cause performance issues and they are the wrong thing to do. A hack to fix this data into a related table used one-time is fine, a hack to continuallly query your database is simply a poor choice. It will cost less time in the long run to fix this cancer at the heart of your database right now. But in general the process to fix this is to split the data out into a related table using some version of fn_split (look up the various implementations of this for a script to create the function). You can use a temp table in your query or do the right thing and fix the database.
If you want to retrieve the result on the basis of Join then why don't you join your both tables on the "registration_id" by using inner-join. And please clearify me you want to perform the join on the active_cc, but its actually not present in your second table. So how you preform join in that case.
I completely agree with #HLGEM, but to solve this particular problem cost will be high.
I had given a try to want you want to achive here. Please modify the join if needed.
Let me know if any further help needed.
Sample Schema
create table tableC (ACTIVITY_ID int, REG_ID int,PROJ_ID int,DOSS_ID int,ACTIVITY_TO int, ACTIVITY_CC varchar(500))
insert into tableC select 4, 1,1,1,1, '3,4';
insert into tableC select 5, 2,2,2,2, '5,6';
insert into tableC select 6, 3,3,3,3, '3,5';
create table tableD (REG_ID int , FIRST_NAME VARCHAR(100), LAST_NAME VARCHAR(100))
insert into tableD select 3, 'Pritam', 'Sharma';
insert into tableD select 4, 'Pratik', 'Gupta';
insert into tableD select 5, 'Niket', 'Vaidya';
insert into tableD select 6, 'Ajinkya', 'Satwa';
Sample Query
with names as
(
select C.ACTIVITY_ID,C.ACTIVITY_CC
,Names = D.FIRST_NAME
from tableC C
inner join tableD D on charindex(cast(D.REG_ID as varchar), C.ACTIVITY_CC) > 0
)
select
C.ACTIVITY_ID,C.REG_ID,PROJ_ID,DOSS_ID,ACTIVITY_TO,ACTIVITY_CC
,Names = stuff
(
(
select ',' + Names
from names n
where n.ACTIVITY_ID = D.REG_ID
for xml path('')
)
, 1
, 1
, ''
)
from tableD D
inner join tableC C on C.ACTIVITY_ID = D.REG_ID
Added to SQLFiddle also
Considering Pratik's structure
CREATE TABLE tableC
(
ACTIVITY_ID int,
REG_ID int,
PROJ_ID int,
DOSS_ID int,
ACTIVITY_TO int,
ACTIVITY_CC varchar(500)
);
INSERT INTO tableC select 4, 1,1,1,1, '3,4';
INSERT INTO tableC select 5, 2,2,2,2, '5,6';
INSERT INTO tableC select 6, 3,3,3,3, '3,5';
CREATE TABLE tableD
(
REG_ID int,
FIRST_NAME VARCHAR(100),
LAST_NAME VARCHAR(100)
);
INSERT INTO tableD select 3, 'Pritam', 'Sharma';
INSERT INTO tableD select 4, 'Pratik', 'Gupta';
INSERT INTO tableD select 5, 'Niket', 'Vaidya';
INSERT INTO tableD select 6, 'Ajinkya', 'Satwa';
You can do this:
SELECT tableD.FIRST_NAME
FROM tableD
JOIN tableC ON tableC.ACTIVITY_CC LIKE CONCAT('%', tableD.REG_ID, '%')
GROUP BY tableD.FIRST_NAME;
OR
SELECT FIRST_NAME
FROM tableD, tableC
WHERE tableC.ACTIVITY_CC LIKE CONCAT('%', tableD.REG_ID, '%')
GROUP BY tableD.FIRST_NAME;

SQL joins with multiple records into one with a default

My 'people' table has one row per person, and that person has a division (not unique) and a company (not unique).
I need to join people to p_features, c_features, d_features on:
people.person=p_features.num_value
people.division=d_features.num_value
people.company=c_features.num_value
... in a way that if there is a record match in p_features/d_features/c_features only, it would be returned, but if it was in 2 or 3 of the tables, the most specific record would be returned.
From my test data below, for example, query for person=1 would return
'FALSE'
person 3 returns maybe, person 4 returns true, and person 9 returns default
The biggest issue is that there are 100 features and I have queries that need to return all of them in one row. My previous attempt was a function which queried on feature,num_value in each table and did a foreach, but 100 features * 4 tables meant 400 reads and it brought the database to a halt it was so slow when I loaded up a few million rows of data.
create table p_features (
num_value int8,
feature varchar(20),
feature_value varchar(128)
);
create table c_features (
num_value int8,
feature varchar(20),
feature_value varchar(128)
);
create table d_features (
num_value int8,
feature varchar(20),
feature_value varchar(128)
);
create table default_features (
feature varchar(20),
feature_value varchar(128)
);
create table people (
person int8 not null,
division int8 not null,
company int8 not null
);
insert into people values (4,5,6);
insert into people values (3,5,6);
insert into people values (1,2,6);
insert into p_features values (4,'WEARING PANTS','TRUE');
insert into c_features values (6,'WEARING PANTS','FALSE');
insert into d_features values (5,'WEARING PANTS','MAYBE');
insert into default_features values('WEARING PANTS','DEFAULT');
You need to transpose the features into rows with a ranking. Here I used a common-table expression. If your database product does not support them, you can use temporary tables to achieve the same effect.
;With RankedFeatures As
(
Select 1 As FeatureRank, P.person, PF.feature, PF.feature_value
From people As P
Join p_features As PF
On PF.num_value = P.person
Union All
Select 2, P.person, PF.feature, PF.feature_value
From people As P
Join d_features As PF
On PF.num_value = P.division
Union All
Select 3, P.person, PF.feature, PF.feature_value
From people As P
Join c_features As PF
On PF.num_value = P.company
Union All
Select 4, P.person, DF.feature, DF.feature_value
From people As P
Cross Join default_features As DF
)
, HighestRankedFeature As
(
Select Min(FeatureRank) As FeatureRank, person
From RankedFeatures
Group By person
)
Select RF.person, RF.FeatureRank, RF.feature, RF.feature_value
From people As P
Join HighestRankedFeature As HRF
On HRF.person = P.person
Join RankedFeatures As RF
On RF.FeatureRank = HRF.FeatureRank
And RF.person = P.person
Order By P.person
I don't know if I had understood very well your question, but to use JOIN, you need your table loaded already and then use the SELECT statement with INNER JOIN, LEFT JOIN or whatever you need to show.
If you post some more information, maybe turn it easy to understand.
There are some aspects of your schema I'm not understanding, like how to relate to the default_features table if there's no match in any of the specific tables. The only possible join condition is on feature, but if there's no match in the other 3 tables, there's no value to join on. So, in my example, I've hard-coded the DEFAULT since I can't think of how else to get it.
Hopefully this can get you started and if you can clarify the model a bit more, the solution can be refined.
select p.person, coalesce(pf.feature_value, df.feature_value, cf.feature_value, 'DEFAULT')
from people p
left join p_features pf
on p.person = pf.num_value
left join d_features df
on p.division = df.num_value
left join c_features cf
on p.company = cf.num_value