SELECT command with a WHERE condition and an INNER JOIN - sql

I'm sure I must be making a trivial mistake here, but I've been searching around for help with this problem and all I can find is information on conditional INNER JOINs.
< EDIT > The problem is that this stored procedure is not returning anything at all. If I type just:
SELECT TOP (6) UserID, Category, Title, SUBSTRING(Article, 0, 200) AS Summary, DatePosted
FROM ContribContent
WHERE (DateFeatured IS NOT NULL)
ORDER BY DateFeatured DESC
Into the console then I get values returned. So it must be something to do with the inner-join? < / EDIT >
The idea is to:
take the content which has been
featured (DateFeatured is NOT NULL)
and place it all into a temporary
table
get the user names and picture from the users table and match them to the values in the temporary table using the UserID value.
sort the temporary table in order of the date each post was featured.
select the top six entries from the table
Here's the code:
ALTER PROCEDURE [dbo].[admin_GetFeaturedContrib]
AS
BEGIN
DECLARE #FeaturedContrib TABLE (
UserID INT,
Category INT,
Title varchar(100),
Summary varchar(200),
DatePosted date,
FirstName varchar(50),
LastName varchar(50),
Picture varchar(100)
)
INSERT INTO #FeaturedContrib
SELECT TOP 6 ContribContent.UserID, ContribContent.Category, ContribContent.Title, SUBSTRING(ContribContent.Article, 0, 200) AS Summary, ContribContent.DatePosted, Users.FirstName, Users.LastName, Users.Picture
FROM ContribContent
INNER JOIN Users
ON ContribContent.UserID = Users.UserID
WHERE ContribContent.DateFeatured IS NOT NULL
ORDER BY ContribContent.DateFeatured DESC
SELECT * FROM #FeaturedContrib
END
There are two data tables involved:
Users - a table storing all of the users and their information.
UserID INT
FirstName varchar(50)
LastName varchar(50)
Picture varchar(50)
etc...
ContribContent
ContribContentID INT
UserID INT
Category INT
Title varchar(100)
Article varchar(MAX)
Picture varchar(50)
DatePosted date
DateFeatured date
Deleted bit
THANKS to anyone who can help out!

Run only -
SELECT TOP 6 ContribContent.UserID, ContribContent.Category, ContribContent.Title, SUBSTRING(ContribContent.Article, 0, 200) AS Summary, ContribContent.DatePosted, Users.FirstName, Users.LastName, Users.Picture
FROM ContribContent
INNER JOIN Users
ON ContribContent.UserID = Users.UserID
WHERE ContribContent.DateFeatured IS NOT NULL
ORDER BY ContribContent.DateFeatured DESC
See what you getting might be an issue with your Where or your join see carefully if you have any data in the first place being returned. My guess is join see if you have matching userids you are joining on...(Hint : Left join maybe your answer)

Related

Needed helpful hand with a bit complicated query

I have a table 'Tasks' with the following structure
[TaskId],[CompanyId], [Year], [Month], [Value]
220,1,2018,1,50553.32
220,2,2018,2,222038.12
and another table where users have permissions to particular companies in table named 'UsersCopmpanies'
[UserId], [CompanyId]
1,1
and the thing is task no. 220 was moved between companies. In January task belonged to copmanyId=1 and than in February this task belonged to copmanyId = 2.
According to the table 'UsersCopmpanies' user does not have permision to compnayid = 2.
What I need to do is to get both rows from table 'Tasks' expect field Value, because user does not have persmission.
Expected result should be:
[TaskId], [CompanyId], [Year], [Month],[Value]
220,1,2018,1,50553.32
220,2,2018,2,(NULL or somenthing else for.example string 'lack of permission')
You can use a left join:
select t.TaskId, t.CompanyId, t.Year, t.Month,
(case when uc.CompanyId is not null then Value end) as Value
from tasks t left join
UsersCompanies uc
on uc.CompanyId = t.CompanyId and uc.UserId = 1;
I think this query using LEFT JOIN can be work at you expected :
CREATE TABLE #MyTasks
(TaskId int,
CompanyId int,
YearCol varchar(50),
MonthCol varchar(50),
SomeValue varchar(50)
);
GO
INSERT INTO #MyTasks
SELECT 220,1,2018,1,50553.32
UNION
SELECT 220,2,2018,2,222038.12
CREATE TABLE #MyUsersCopmpanies
(UserId int PRIMARY KEY,
CompanyId varchar(50)
);
GO
INSERT INTO #MyUsersCopmpanies
SELECT 1,1
DECLARE #MyUserParam INT = 1;
SELECT #MyTasks.TaskId, #MyTasks.CompanyId, #MyTasks.YearCol, #MyTasks.MonthCol,
CASE WHEN #MyUsersCopmpanies.UserId IS NOT NULL THEN #MyTasks.SomeValue ELSE 'lack of permission' END AS 'ValueTaskByPermissions'
FROM #MyTasks
LEFT JOIN #MyUsersCopmpanies ON #MyUsersCopmpanies.CompanyId = #MyTasks.CompanyId AND #MyUsersCopmpanies.UserId = #MyUserParam;
DROP TABLE #MyTasks
DROP TABLE #MyUsersCopmpanies
RESULT :
TaskId CompanyId YearCol MonthCol ValueTaskByPermissions
220 1 2018 1 50553.32
220 2 2018 2 lack of permission
Some code :
SELECT t.taskid,t.companyid,t.year,t.month,
(CASE WHEN u.companyid IS NOT NULL THEN t.value ELSE "lack of permission" end) AS ValueData
FROM `x_task` t LEFT JOIN x_userscopmpanies u ON u.companyid = t.companyid

Increase MS SQL transaction performance

If you're missing information, I will attach them if requested.
Workspace
I have a database running on a MS SQL 2012 standard edition of this kind:
tables:
users(id, softId (not unique), birthdate)
rows: 10.5 million
indexes: all three columns, birthdate(clustered)
docs(docId, userId, creationDate, deleteDate, lastname, forename, classificationId)
rows: 23 million
indexes: lastname, forename, docId, creationDate, userID(clustered)
notice: in this specific case the names are related to the docs, not to the userId
classifications(id, description)
rows: 200
three tables "data"
rows: 10, 13 and 0.3 million
indexes: docIds
relations:
users to docs: 1 to n
classifications to docs: 1 to n
docs to data-tables: 1 to n
To select the complete records I am actually on following statements:
Server-Execution-Time 16 seconds
SELECT * FROM (
select * from docs
where userID in (
select distinct userID from users where softId like '...'
)
) as doc
LEFT JOIN users on users.userID = doc.userId
LEFT JOIN classifications on classifications.id = doc.classificationId
LEFT JOIN data1 on data1.docId = doc.docId
LEFT JOIN data2 on data2.docId = doc.docId
LEFT JOIN data3 on data3.docId = doc.docId;
Updated - now 15 seconds
SELECT
docID, calssificationId, classificationDescription,
userId, softId, forename, lastname, birthdate,
data1.id, data1.date, data2.id, data2.date, data3.id, data3.date,
FROM docs
JOIN users on users.userID = doc.userId AND softId like '...'
LEFT JOIN classifications on classifications.id = doc.classificationId
LEFT JOIN data1 on data1.docId = doc.docId
LEFT JOIN data2 on data2.docId = doc.docId
LEFT JOIN data3 on data3.docId = doc.docId;
execution plans
execution plan
Server-Execution-Time 17 seconds
DECLARE #userIDs table( id bigint );
DECLARE #docIDs table( id bigint );
insert into #userIDs select userID from users where softId like '...';
insert into #docIDs select docId from docs where userId in ( select id from #userIDs);
SELECT * FROM users where userID in ( select id from #userIDs);
SELECT * FROM docs where docID in (select id from #docIDs);
SELECT * FROM data1 where data1.docId in (select id from #docIDs);
SELECT * FROM data2 where data2.docId in (select id from #docIDs);
SELECT * FROM data3 where data3.docId in (select id from #docIDs);
GO
Updated - now 14 seconds
DECLARE #userIDs table( id bigint, softId varchar(12), birthdate varchar(8) );
DECLARE #docIDs table( id bigint, classification bigint, capture_date datetime, userId bigint, lastname varchar(50), forename varchar(50) );
INSERT INTO #userIDs select userID, softId, birthdate from users where softId like '...';
INSERT INTO #docIDs select docID, classification, capture_date, userID, lastname, forename from docs where userID in ( select id from #userIDs);
SELECT * FROM #userIDs;
SELECT * FROM #docIDs;
SELECT [only needed fields] FROM data1 where docID in (select id from #docIDs);
SELECT [only needed fields] FROM data2 where docID in (select id from #docIDs);
SELECT [only needed fields] FROM data3 where docID in (select id from #docIDs);
execution plans
execution plan userIds
execution plan docIds
execution plan userIds output
execution plan data1
General Updates
#AntonínLejsek suggested to define the docId of documents as a clustered index and the pkId as non-clustered. This changed the execution-time as follow:
Join-Statement: -1 second
Multi-Select-Statement: -5 seconds
I checked the indexes again and changed the included columns, now they have the execution-time:
Join-Statement: 4 seconds
Multi-Select-Statement: 6 seconds
The "simple" question
Do somebody have suggestions to reduce the executiontime?
I would phrase the logic as:
I would get rid of the first subquery and just do the necessary work on the users table:
SELECT *
FROM docs JOIN
users
ON users.userID = doc.userId AND softId LIKE '...' LEFT JOIN
. . .
The logic in the IN is unnecessary if you are doing a JOIN anyway.
Note: This might not help much, because your query appears to be returning lots of data, both in columns and rows.
I see two different databases in the plan, I would try to test it in one database first.
The database design is weird. You have clustered index on birthdate. As it is not unique, database has to make up another 4B number for making it unique. So You have 12B key in every nonclustered index, which is space and performance inefficient. You do not even have id included in the nonclustered index, so it has to be looked up, which is time wasting. In most cases You should cluster on primary key and that should be id.
--Deleted-- while softIds is almost unique, this paragraph became irelevant.
Add clustered indexes on your table variables by defining primary keys.
DECLARE #userIDs table( id bigint primary key, softId varchar(12), birthdate varchar(8) );
DECLARE #docIDs table( id bigint primary key, classification bigint, capture_date datetime, userId bigint, lastname varchar(50), forename varchar(50) );

NOT EXISTS returning no rows

This is not a question about the difference between NOT EXISTS and IN.
I just can't seem to get this sql working right.
The logic seems ok, but I'm missing something.
And I have searched everywhere, even in my years and years of notes.
One table named CompanyAccountantRef has 3 fields. ID, CompanyID, and AccountantID.
Currently in the table:
ID CompanyID AccountantID
8 6706 346388
9 6706 346256
10 6706 26263
11 363392 358951
Then this sql is not bringing back the correct row:
DECLARE #CompanyID INT = 363392
DECLARE #AccountIDs TABLE (ID INT)
INSERT INTO #AccountIDs (ID) VALUES (358951)
INSERT INTO #AccountIDs (ID) VALUES (26263)
SELECT #CompanyID AS CompanyID, a.ID
FROM #AccountIDs a
WHERE NOT EXISTS(
SELECT *
FROM CompanyAccountantRef
WHERE CompanyID = #CompanyID
AND AccountantID IN (SELECT ID FROM #AccountIDs))
It should bring back
CompanyID AccountantID
363392 26263
And yes, an accountant can have more than one company.
What am I missing here? Is it the use of the IN that breaks it?
I've tried several different way including joins with no luck.
Thanks.
I'm not sure why you are confused. Consider the subquery:
SELECT *
FROM CompanyAccountantRef
WHERE CompanyID = #CompanyID AND
AccountantID IN (SELECT ID FROM #AccountIDs)
This returns one row, because CompanyAccountantRef has one matching row and its accountant id is 358951. There is a match in #AccountIds. Hence, the query returns one row.
Hence, the NOT EXISTS is false. And no rows are returned.
I suspect that you want a correlated subquery of some sort. I'm not sure what logic you are looking for. The logic you have doesn't seem particularly useful (either it returns all rows in #AccountIds or none).
If I had to guess, you a looking for something like:
SELECT #CompanyID AS CompanyID, a.ID
FROM #AccountIDs a
WHERE NOT EXISTS (SELECT 1
FROM CompanyAccountantRef car
WHERE car.CompanyID = #CompanyID AND
car.AccountantID = a.ID
);
At the very least, this returns the row you are looking for.
select #CompanyID, ID
from AccountIDs
except
select #CompanyID, AccountantID
from CompanyAccountantRef
where CompanyID = #CompanyID
and AccountantID in (SELECT ID FROM #AccountIDs)

SQL for list of columns values that change against another column

I have a table of Events that contains Team ID's and Client ID's. Although the two columns usually have the same corresponding values the TeamID might change from time to time against a particular ClientID.
I need to get a list of Client ID's whose Team ID's will have changed and the teamids they have changed to
I started off with
SELECT ClientID AS CID
FROM
(SELECT TeamID, count(*) as Counter
FROM `vEvents`
GROUP BY `ClintID`) AS tbl WHERE Counter > 1
But I think I'm barking up the wrong tree. Any help greatly appreciated
Andrew
May this help you or give your hint
create table Clients (ID int identity(1,1),
TeamID int not null,
ClientID int not null,
LastModifiedDate datetime not null
)
insert Clients values
(1,1001,DATEADD(mi,-5,GETDATE())),
(2,1002,DATEADD(mi,-7,GETDATE())),
(3,1001,GETDATE())
SELECT ClientID, TeamID
FROM Clients
WHERE ClientID in (select ClientID from Clients group by ClientID having COUNT(TeamID)>1)

Database design - Multiple 1 to many relationships

What would be the best way to model 1 table with multiple 1 to many relatiionships.
With the above schema if Report contains 1 row, Grant 2 rows and Donation 12. When I join the three together I end up with a Cartesian product and result set of 24. Report joins to Grant and creates 2 rows, then Donation joins on that to make 24 rows.
Is there a better way to model this to avoid the caresian product?
example code
DECLARE #Report
TABLE (
ReportID INT,
Name VARCHAR(50)
)
INSERT
INTO #Report
(
ReportID,
Name
)
SELECT 1,'Report1'
DECLARE #Grant
TABLE (
GrantID INT IDENTITY(1,1) PRIMARY KEY(GrantID),
GrantMaker VARCHAR(50),
Amount DECIMAL(10,2),
ReportID INT
)
INSERT
INTO #Grant
(
GrantMaker,
Amount,
ReportID
)
SELECT 'Grantmaker1',10,1
UNION ALL
SELECT 'Grantmaker2',999,1
DECLARE #Donation
TABLE (
DonationID INT IDENTITY(1,1) PRIMARY KEY(DonationID),
DonationMaker VARCHAR(50),
Amount DECIMAL(10,2),
ReportID INT
)
INSERT
INTO #Donation
(
DonationMaker,
Amount,
ReportID
)
SELECT 'Grantmaker1',10,1
UNION ALL
SELECT 'Grantmaker2',3434,1
UNION ALL
SELECT 'Grantmaker3',45645,1
UNION ALL
SELECT 'Grantmaker4',3,1
UNION ALL
SELECT 'Grantmaker5',34,1
UNION ALL
SELECT 'Grantmaker6',23,1
UNION ALL
SELECT 'Grantmaker7',67,1
UNION ALL
SELECT 'Grantmaker8',78,1
UNION ALL
SELECT 'Grantmaker9',98,1
UNION ALL
SELECT 'Grantmaker10',43,1
UNION ALL
SELECT 'Grantmaker11',107,1
UNION ALL
SELECT 'Grantmaker12',111,1
SELECT *
FROM #Report r
INNER JOIN
#Grant g
ON r.ReportID = g.ReportID
INNER JOIN
#Donation d
ON r.ReportID = d.ReportID
Update 1 2011-03-07 15:20
Cheers for the feedback so far, to add to this scenario there are also 15 other 1 to many relationships coming from the one report table. These tables can't for various business reasons be grouped together.
Is there any relationship at all between Grants and Donations? If there isn't, does it make sense to pull back a query that shows a pseudo relationship between them?
I'd do one query for grants:
SELECT r.*, g.*
FROM #Report r
JOIN #Grant g ON r.ReportID = g.ReportID
And another for donations:
SELECT r.*, d.*
FROM #Report r
JOIN #Donation d ON r.ReportID = d.ReportID
Then let your application show the appropriate data.
However, if Grants and Donations are similar, then just make a more generic table such as Contributions.
Contributions
-------------
ContributionID (PK)
Maker
Amount
Type
ReportID (FK)
Now your query is:
SELECT r.*, c.*
FROM #Report r
JOIN #Contribution c ON r.ReportID = c.ReportID
WHERE c.Type = 'Grant' -- or Donation, depending on the application
If you're going to join on ReportID, then no, you can't avoid a lot of rows. When you omit the table "Report", and just join "Donation" to "Grant" on ReportId, you still get 24 rows.
SELECT *
FROM Grant g
INNER JOIN
Donation d
ON g.ReportID = d.ReportID
But the essential point is that it doesn't make sense in the real world to match up donations and grants. They're completely independent things that essentially have nothing to do with each other.
In the database, the statement immediately above will join each row in Grants to every matching row in Donation. The resulting 24 rows really shouldn't surprise you.
When you need to present independent things to the user, you should use a report writer or web application (for example) that selects the independent things, well, independently. Select donations and put them into one section of a report or web page, then select grants and put them into another section of the report or web page, and so on.
If the table "Report" is supposed to help you record which sections go into a particular report, then you need a structure more like this:
create table reports (
reportid integer primary key,
report_name varchar(35) not null unique
);
create table report_sections (
reportid integer not null references reports (reportid),
section_name varchar(35), -- Might want to reference a table of section names
section_order integer not null,
primary key (reportid, section_name)
);
The donation and grant tables look almost identical. You could make them one table and add a column that is something like DonationType. Would reduce complexity by 1 table. Now if donations and grants are completely different and have different subtables associated with them then keeping them seperate and only joining on one at a time would be ideal.