Restrict SQL output to items found only in subquery - sql

Ok, given this example, can you point me in the right direction to restrict the output of this query to results found only in the where clause. I'll explain more..
SELECT
ServerName=substring(MN.object_text,patindex ('%Caption %',MN.object_text)+11,patindex('%"%',substring(MN.object_text,patindex ('%Caption %',MN.object_text)+11,80))-1)
/* ,MN.object_text */, p.name
FROM
[openview].[dbo].[sto_ov_managednode] MN
left outer join [openview].[dbo].[OV_PM_PolicyOnNode] PON
on pon.nodeid = mn.name
left outer join [openview].[dbo].[OV_PM_PolicyVersion] PV
on PV.policyversionid = pon.policyversionid
left outer join [openview].[dbo].[OV_PM_Policy] P
on P.PolicyId = pv.policyid
where p.name not in (select Name from dbo.OV_PM_Policy where PolicyId = any(select PolicyId from dbo.OV_PM_PolicyGroupAssignment where GroupId = '18681abc-097d-41cd-9782-e28d9a9f5fc4'))
and substring(MN.object_text,patindex ('%AgentBinaryFormatId%',MN.object_text)+22,1) <> '0' /* exclude non-managed nodes */
and substring(MN.object_text,patindex ('%OsVersionId%',MN.object_text)+14,2) = '18' /* include only Windows OS devices */
ORDER BY ServerName, name;
Lets say this returns all the servernames with a p.name not in my query. That's what it is supposed to do as written... but I only want that servername if it doesn't have one of those policies...and only if it doesn't have one of those... not listing other policies it may have.. but aren't in that result set... I've tried different joins, and used not in.... exists not exists... the issue.. is, when I use those.. it doesn't really change anything.
Think of a folder structure..... that p.name is looking in a folder and finding all the policy names inside. There are many folders and many other policies.... but in this I only care about those in that folder. So if server A has all the policies in that folder I don't want to see it.. If it has other policies I don't care... but if it's missing even one of the policies from that given folder I want to know about it.
So basically I want the output it is giving me currently.. but only if the policy found was in that group to begin with. So I need to restrict my output to only return servers missing policies from that group.
Updated -- sqlfiddle information and better example...thanks Mark for the sqlfiddle setup
create table sto_ov_managednode (
object_text varchar(100),
name varchar(100)
);
create table OV_PM_PolicyOnNode (
nodeid varchar(100),
policyversionid varchar(100)
);
create table OV_PM_PolicyVersion (
policyversionid varchar(100) unique,
policyid varchar(100)
);
create table OV_PM_Policy (
Name varchar(100),
PolicyId varchar(100)
);
create table OV_PM_PolicyGroupAssignment (
PolicyId varchar(100),
GroupId varchar(100),
PolicyVerisonId varchar(100) unique
);
insert into sto_ov_managednode values ('Caption ---Server1"---AgentBinaryFormatId---OsVersionId---18--','node1');
insert into sto_ov_managednode values ('Caption ---Server2"---AgentBinaryFormatId---OsVersionId---18--','node2');
insert into OV_PM_PolicyOnNode values ('node1','policyversionID1');
insert into OV_PM_PolicyOnNode values ('node1','policyversionID4');
insert into OV_PM_PolicyOnNode values ('node2','policyversionID1');
insert into OV_PM_PolicyVersion values ('policyversionid1','policyid1');
insert into OV_PM_PolicyVersion values ('policyversionid2','policyid1');
insert into OV_PM_PolicyVersion values ('policyversionid3','policyid2');
insert into OV_PM_PolicyVersion values ('policyversionid4','policyid2');
insert into OV_PM_PolicyVersion values ('policyversionid5','policyid3');
insert into OV_PM_PolicyVersion values ('policyversionid6','policyid3');
insert into OV_PM_Policy values ('policy A','policyid1');
insert into OV_PM_Policy values ('policy B','policyid2');
insert into OV_PM_Policy values ('policy C','policyid3');
insert into OV_PM_PolicyGroupAssignment values ('policyid1','Base Windows','policyversionid2');
insert into OV_PM_PolicyGroupAssignment values ('policyid2','Base Windows','policyversionid4');
insert into OV_PM_PolicyGroupAssignment values ('policyid3','Extra Windows','policyversionid5');
Now the output is this..
nodeName policyName
node1 policy C
node2 policy B
node2 policy C
You'll notice that this is basically correct.. but I don't want to see Policy C as it's not in the Base Windows Group.... I only need to see a policy if it's missing from a server...AND is included in the group I used to search for..
New SqlFiddle
Final Update
This is the final sql statement that did in fact work. Thanks for the effort, I appreciate it.
select ServerName=substring(MN.object_text,patindex ('%Caption %',MN.object_text)+11,patindex('%"%',substring(MN.object_text,patindex ('%Caption %',MN.object_text)+11,80))-1), "Policy" = P.name
FROM OV_PM_PolicyGroupAssignment PGA
left join OV_PM_Policy P on PGA.PolicyId = P.PolicyId
left join OV_PM_PolicyVersion PV on P.PolicyId = PV.policyid
cross join sto_ov_managednode MN
where PGA.GroupId = '18681abc-097d-41cd-9782-e28d9a9f5fc4'
and substring(MN.object_text,patindex ('%AgentBinaryFormatId%',MN.object_text)+22,1) <> '0' /* exclude non-managed nodes */
and substring(MN.object_text,patindex ('%OsVersionId%',MN.object_text)+14,2) = '18' /* include only Windows OS devices */
except
select ServerName=substring(MN.object_text,patindex ('%Caption %',MN.object_text)+11,patindex('%"%',substring(MN.object_text,patindex ('%Caption %',MN.object_text)+11,80))-1), P.name as policyName
from sto_ov_managednode MN
left join OV_PM_PolicyOnNode PON on pon.nodeid = mn.name
left join OV_PM_PolicyVersion PV on PV.policyversionid = pon.policyversionid
left join OV_PM_Policy P on P.PolicyId = pv.policyid
left join OV_PM_PolicyGroupAssignment PGA on P.PolicyId = PGA.PolicyId
where PGA.GroupId = '18681abc-097d-41cd-9782-e28d9a9f5fc4'
Order by ServerName, Policy;

I hope I understood your schema enough to correctly respond.
SQLFiddle: http://sqlfiddle.com/#!6/baffd/35
Set up data:
create table sto_ov_managednode (
object_text varchar(100),
name varchar(100)
);
create table OV_PM_PolicyOnNode (
nodeid varchar(100),
policyversionid varchar(100)
);
create table OV_PM_PolicyVersion (
policyversionid varchar(100),
policyid varchar(100)
);
create table OV_PM_Policy (
name varchar(100),
PolicyId varchar(100)
);
create table OV_PM_PolicyGroupAssignment (
PolicyId varchar(100),
GroupId varchar(100)
);
insert into sto_ov_managednode values ('Caption ---Server1"---AgentBinaryFormatId---OsVersionId---18--','node1');
insert into sto_ov_managednode values ('Caption ---Server2"---AgentBinaryFormatId---OsVersionId---18--','node2');
insert into OV_PM_PolicyOnNode values ('node1','policyversion1');
insert into OV_PM_PolicyOnNode values ('node1','policyversion2');
insert into OV_PM_PolicyOnNode values ('node2','policyversion1');
insert into OV_PM_PolicyVersion values ('policyversion1','policyid1');
insert into OV_PM_PolicyVersion values ('policyversion2','policyid2');
insert into OV_PM_Policy values ('policy A','policyid1');
insert into OV_PM_Policy values ('policy B','policyid1');
insert into OV_PM_Policy values ('policy C','policyid2');
insert into OV_PM_PolicyGroupAssignment values ('policyid1','18681abc-097d-41cd-9782-e28d9a9f5fc4');
insert into OV_PM_PolicyGroupAssignment values ('policyid2','18681abc-097d-41cd-9782-e28d9a9f5fc4');
Query:
select MN.name as nodeName, P.name as policyName
FROM OV_PM_PolicyGroupAssignment PGA
left join OV_PM_Policy P on PGA.PolicyId = P.PolicyId
left join OV_PM_PolicyVersion PV on P.PolicyId = PV.policyid
cross join sto_ov_managednode MN
where PGA.GroupId = 'Base Windows'
except
select MN.name as nodeName, P.name as policyName
from sto_ov_managednode MN
left join OV_PM_PolicyOnNode PON on pon.nodeid = mn.name
left join OV_PM_PolicyVersion PV on PV.policyversionid = pon.policyversionid
left join OV_PM_Policy P on P.PolicyId = pv.policyid
left join OV_PM_PolicyGroupAssignment PGA on P.PolicyId = PGA.PolicyId
where PGA.GroupId = 'Base Windows'
order by nodeName, policyName;
The top part of the query gets all of the policies for the policy group and does a cross join with the nodes to list one policy for each node regardless of whether the policy exists or not. Then I use EXCEPT to remove the existing node policies.
Result:
nodeName policyName
node2 policy C

Related

Insert into a table based on the foreign keys from other tables

I have one table containing multiple foreign keys. When I insert values into other tables, this table needs to show the inserted foreign keys. Also, ContactDate should be the current date.
When I try to execute the following, I only have inserted ContactDetails, and the rest are all NULL.
EXEC usp_addQuickContacts 'minnie.mouse#disney.com','John
Lasseter','Minnie getting Homework Support from John','Homework
Support'
I have also tried inserting them one by one instead of the inner join, but the result doesn't line up in the same row.
CREATE OR ALTER PROCEDURE usp_addQuickContacts
(
#StudentEmail VARCHAR(100),
#EmployeeName NVARCHAR(100),
#ContactDetails NVARCHAR(200),
#ContactType NVARCHAR(100)
)
AS
BEGIN
IF #contactDetails NOT IN (SELECT ContactDetails FROM StudentContacts)
INSERT INTO StudentContacts(ContactDetails)
VALUES (#contactDetails )
IF #StudentEmail NOT IN (SELECT Email From StudentInformation)
INSERT INTO StudentInformation(Email)
VALUES (#StudentEmail )
IF #contactType NOT IN (SELECT ContactType FROM ContactType)
INSERT INTO ContactType (ContactType)
VALUES (#contactType)
IF #EmployeeName NOT IN (SELECT EmployeeName FROM Employees)
INSERT INTO Employees (EmployeeName)
VALUES (#EmployeeName )
INSERT INTO StudentContacts(StudentID, EmployeeID, ContactDetails, ContactDate, ContactTypeID)
SELECT si.StudentID, e.EmployeeID, sc.ContactDetails, sc.ContactDate,ct.ContactTypeID
FROM StudentContacts sc
INNER JOIN StudentInformation si ON sc.StudentID = si.StudentID
INNER JOIN Employees e ON e.EmployeeID = sc.EmployeeID
INNER JOIN ContactType ct ON ct.ContactTypeID = sc.ContactTypeID
INNER JOIN StudentContacts scs ON scs.ContactDate = sc.ContactDate
WHERE (ct.ContactType= #ContactType) AND (si.Email = #StudentEmail) AND (e.EmployeeNAME = #EmployeeName ) AND (sc.ContactDetails = #contactDetails) AND (sc.ContactDate = GETDATE())
END
As I understand from your code that there would may be problem in below part
(sc.ContactDate = GETDATE())
Casting is not a good Option in where condition but you can try with as (Cast(sc.ContactDate as Date) = Cast(GETDATE()) as Date)

How to select all records that do not have a *specific* record in a sub table

In SQL Server I am trying to select parcels that do not have a particular movement. Parcels can have zero or more movements. Movements are described in a third table.
I have some parcels
IF OBJECT_ID('tempdb..#Parcels','U') IS NOT NULL
BEGIN
DROP TABLE #Parcels
END;
CREATE TABLE #Parcels(
Id int
,LocalBarcode nvarchar(50)
,ForeignBarcode nvarchar(50)
)
INSERT INTO #Parcels VALUES (1, 'Sabc1', NULL)
INSERT INTO #Parcels VALUES (2, 'Sabc2', NULL)
INSERT INTO #Parcels VALUES (3, 'Sabc3', 'def1')
INSERT INTO #Parcels VALUES (4, 'xabc', NULL)
Associated with parcels are movements
IF OBJECT_ID('tempdb..#Movements','U') IS NOT NULL
BEGIN
DROP TABLE #Movements
END;
CREATE TABLE #Movements(
ParcelId int
,MovementCode nvarchar(3)
)
INSERT INTO #Movements VALUES (1,'MV1')
INSERT INTO #Movements VALUES (2,'MV1')
INSERT INTO #Movements VALUES (2,'MV2')
INSERT INTO #Movements VALUES (2,'MV3')
INSERT INTO #Movements VALUES (3,'MV1')
INSERT INTO #Movements VALUES (3,'MV2')
INSERT INTO #Movements VALUES (3,'MV3')
The movements are described in detail in a third table
IF OBJECT_ID('tempdb..#MovementDescriptions','U') IS NOT NULL
BEGIN
DROP TABLE #MovementDescriptions
END;
CREATE TABLE #MovementDescriptions(
MovementCode nvarchar(3)
,MovementDesc nvarchar(4)
)
INSERT INTO #MovementDescriptions VALUES ('MV1','Mov1')
INSERT INTO #MovementDescriptions VALUES ('MV2','Mov2')
INSERT INTO #MovementDescriptions VALUES ('MV3','Mov3');
I would like all parcels
that have no foreign barcode
and local barcode starts with S
and parcel has no Mov2 movement (the parcel can have other movements or no movements at all)
So for the above sample data I am expecting parcel Sabc1
Here is my attempt (which does not work)
WITH ParcelsWithNoForeignBarcodeAndNoMove2
AS (
SELECT
P.Id AS Id
,P.LocalBarcode AS LocalBarcode
,M.MovementCode
,MD.MovementDesc
,ROW_NUMBER() OVER (
PARTITION BY P.Id
ORDER BY P.LocalBarcode
) AS [RowNumber]
FROM #Parcels P
LEFT JOIN #Movements M ON M.ParcelId = P.Id
LEFT JOIN #MovementDescriptions MD ON MD.MovementCode = M.MovementCode AND MD.MovementDesc = 'Mov2'
WHERE
UPPER(P.LocalBarcode) LIKE 'S%'
AND P.ForeignBarcode IS NULL
AND MD.MovementCode IS NULL
)
SELECT
S.Id
,S.LocalBarcode
FROM ParcelsWithNoForeignBarcodeAndNoMove2 S
WHERE
S.RowNumber = 1
You're looking for not exists. Presumably also from your use of upper your collation is case-sensitive. From your simple description, you need:
select *
from #Parcels p
where p.ForeignBarcode is null
and upper(p.LocalBarcode) like 'S%'
and not exists (
select * from #Movements m
where m.ParcelId=p.Id and m.MovementCode='Mv2'
)
SELECT P.* FROM
#Parcels P
INNER JOIN (
SELECT ParcelId, COUNT(MovementCode)MovementCode FROM #Movements WHERE MovementCode!='MV2' GROUP BY ParcelId HAVING COUNT(MovementCode)=1
)T ON P.ID=T.ParcelId

Insert into join table values per each of main table

I have a table called StoreTbl to store the Stores/Markets and this table has a Boolean field called AvailableToAllCities
and there is another Table called CityTbl
And There is a join Table between them called StoreCityJoinTbl
The manager asked me to remove the field AvailableToAllCities (or not use it anymore); So I need to insert to the join table all cities for each Store,
Can I do this without use for-loop?
Without any kind of DDL, I've had to create my own, and used very limited data. This should, however, be enough to get you there:
USE Sandbox;
GO
--Sample data set up
CREATE TABLE Store (StoreID int IDENTITY(1,1), StoreName varchar(50), AvailableToAllCities bit)
CREATE TABLE City (CityID int IDENTITY(1,1), CityName varchar(50));
CREATE TABLE CityStores (ID int IDENTITY(1,1), StoreID int, CityID int)
GO
INSERT INTO City (CityName)
VALUES ('London'),('New York'),('Syndey'),('Washington'),('Paris'),('Berlin'),('Shanghai'),('Tokyo');
INSERT INTO Store (StoreName, AvailableToAllCities)
VALUES ('sdgfkljasghdbfkl',1),
('dsfjklgh',0),
('sdlafiugasdljkbfh',1),
('asdfhjklgasdfjkl',1),
('sdjlhfbvgajldavfhkl',0);
INSERT INTO CityStores (StoreID, CityID)
VALUES (2,1),(2,3),(2,6),
(5,1),(5,2),(5,7),(5,8);
GO
--So your current data looks like this
SELECT S.StoreName, C.CityName
FROM Store S
LEFT JOIN CityStores CS ON S.StoreID = CS.StoreID
JOIN City C ON CS.CityID = C.CityID
OR S.AvailableToAllCities = 1;
GO
--And now the the solution
INSERT INTO CityStores (StoreID,CityID)
SELECT S.StoreID, C.CityID
FROM Store S
CROSS JOIN City C
WHERE S.AvailableToAllCities = 1;
GO
--Drop the old column
ALTER TABLE Store DROP COLUMN AvailableToAllCities;
GO
--And now the new query:
SELECT S.StoreName, C.CityName
FROM Store S
JOIN CityStores CS ON S.StoreID = CS.StoreID
JOIN City C ON CS.CityID = C.CityID;
GO
--Clean up
DROP TABLE Store;
DROP TABLE City;
DROP TABLE CityStores;

How can I pull data from multiple sql tables using a join statement

I'm designing a simple in-office ticket system, and would like to include a field for the party responsible for the next action. To do so right this moment I'm thinking of using tableName and tableID as specifiers for the specific responsible party (could be a technician, customer, or third party, all in different tables)
It would be fine to pull that data in and run another select call using the name of the table as a parameter, but the extra data flow slows things down significantly.
Is there a way to use a single join statement to return the details of the party with a column for the table name and one for the individual table id or is there a better way to store the data from multiple potential tables?
You can use left join to achieve your requirement :-
Set Nocount On;
Declare #OfficeTickets Table
(
Id Int Identity(1,1)
,Column1 Varchar(100)
,PartyType Varchar(1)
,TechnicianId Int Null
,CustomerId Int Null
,ThirdPartyId Int Null
)
Declare #OfficeTickets1 Table
(
Id Int Identity(1,1)
,Column1 Varchar(100)
,TableName Varchar(100)
,TableId Int Null
)
Declare #Technician Table
(
Id Int Identity(1,1)
,TechnicianName Varchar(100)
)
Declare #Customers Table
(
Id Int Identity(1,1)
,CustomerName Varchar(100)
)
Declare #ThirdParty Table
(
Id Int Identity(1,1)
,ThirdPartyName Varchar(100)
)
Insert Into #Technician(TechnicianName) Values
('Technician_1')
,('Technician_2')
,('Technician_3')
Insert Into #Customers(CustomerName) Values
('Customer_1')
,('Customer_2')
,('Customer_3')
Insert Into #ThirdParty(ThirdPartyName) Values
('ThirdParty_1')
,('ThirdParty_2')
,('ThirdParty_3')
,('ThirdParty_4')
Insert Into #OfficeTickets(Column1,PartyType,TechnicianId,CustomerId,ThirdPartyId) Values
('ABC','T',3,Null,Null)
,('XYZ','C',Null,2,Null)
,('PUQ','P',Null,Null,4)
Insert Into #OfficeTickets1(Column1,TableName,TableId) Values
('ABC','Technician',3)
,('XYZ','Customers',2)
,('PUQ','ThirdParty',4)
---- taken separate columns for parties
Select ot.Id
,ot.Column1
,t.TechnicianName
,c.CustomerName
,tp.ThirdPartyName
From #OfficeTickets As ot
Left Join #Technician As t On ot.PartyType = 'T' And ot.TechnicianId = t.Id
Left Join #Customers As c On ot.PartyType = 'C' And ot.CustomerId = c.Id
Left Join #ThirdParty As tp On ot.PartyType = 'P' And ot.ThirdPartyId = tp.Id
---- by TableName and TableId
Select ot.Id
,ot.Column1
,t.TechnicianName
,c.CustomerName
,tp.ThirdPartyName
From #OfficeTickets1 As ot
Left Join #Technician As t On ot.TableName = 'Technician' And ot.TableId = t.Id
Left Join #Customers As c On ot.TableName = 'Customers' And ot.TableId = c.Id
Left Join #ThirdParty As tp On ot.TableName = 'ThirdParty' And ot.TableId = tp.Id
output:-

SQL Server 2005 Pivot Table question

I have an Entity-Value set of tables, and would like to pivot the results.
Here's the effect that I'm looking for, except you see that the SELECT stmt using Common Table Expressions isn't working exactly right yet.
My question is: Am I on the right track, or is there some sort of easy pivot command?
USE TempDB
Declare #Person TABLE(
PersonID Int Identity(101,1))
INSERT INTO #Person DEFAULT VALUES
INSERT INTO #Person DEFAULT VALUES
INSERT INTO #Person DEFAULT VALUES
INSERT INTO #Person DEFAULT VALUES
DECLARE #Attribute TABLE(
AttributeID Int Identity(10,1) PRIMARY KEY,
AttributeName Varchar(MAX))
INSERT INTO #Attribute(AttributeName) VALUES('Firstname')
INSERT INTO #Attribute(AttributeName) VALUES('Lastname')
DECLARE #Pat TABLE( -- A Person's Attributes
PatID Int Identity,
PersonID Int,
AttributeID Int,
PatValue Varchar(MAX)
)
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(101,10,'John')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(102,10,'Paul')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(103,10,'George')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(104,10,'Ringo')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(101,11,'Lennon')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(102,11,'McCartney')
INSERT INTO #Pat(PersonID,AttributeID,PatValue) VALUES(103,11,'Harrison')
SELECT Pat.PersonID,AttributeName,PatValue
FROM #Pat Pat
INNER JOIN #Person Person
ON Pat.PersonID = Person.PersonID
INNER JOIN #Attribute Attribute
ON Pat.AttributeID=Attribute.AttributeID
--
;WITH CTE1 AS(
SELECT PersonID,PatValue AS FirstName
FROM #Pat Pat
INNER JOIN #Attribute Attribute
ON Pat.AttributeID=Attribute.AttributeID
WHERE AttributeName='FirstName'
)
,CTE2 AS(
SELECT PersonID,PatValue AS LastName
FROM #Pat Pat
INNER JOIN #Attribute Attribute
ON Pat.AttributeID=Attribute.AttributeID
WHERE AttributeName='LastName'
)
SELECT Pat.PersonID,FirstName,LastName
FROM #Pat Pat
LEFT OUTER JOIN CTE1
ON Pat.PersonID=CTE1.PersonID
LEFT OUTER JOIN CTE2
ON Pat.PersonID=CTE2.PersonID
ORDER BY PersonID
I just want a list of the 4 people, with their firstname and lastname.
Good example Here
Query in your case would look like this:
SELECT PersonId, FirstName, LastName
FROM
(
-- your query
SELECT Pat.PersonID,AttributeName,PatValue
FROM #Pat Pat
INNER JOIN #Person Person
ON Pat.PersonID = Person.PersonID
INNER JOIN #Attribute Attribute
ON Pat.AttributeID=Attribute.AttributeID
) up
PIVOT (MAX(PatValue) FOR AttributeName IN (FirstName, LastName)) AS pvt