How to add new column with conditional values? - sql

I tried to add a new column with values which is conditional also. And Getting below error -
Subqueries are not allowed in this context. Only scalar expressions are allowed.
Add Column SQL:
IF NOT EXISTS(SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = 'Dbo'
AND TABLE_NAME = 'User'
AND COLUMN_NAME = 'CanEdit')
BEGIN
ALTER TABLE [User]
ADD CanEdit
AS
(CASE WHEN IdUser IN (SELECT u.IdUser
FROM [User] u INNER JOIN UserRole Usrl
ON u.IdUser = Usrl.IdUser INNER JOIN [Role] Rl
ON Usrl.IdRole = Rl.IdRole AND Rl.[Name] = 'Admin') THEN 1
ELSE 0
END)
END

Related

Excluding a column from an inner join in PostgreSQL

I am trying to exclude a column (county) that is shared by both table so I can do a LEFT JOIN in a query. This is what I thought would work but there seems to be some issues (below produces the ERROR: syntax error at or near "LEFT"). What can I do to get this work?
CREATE TABLE levee_prioritization.svi_justice_communities_joined AS
SELECT * FROM ((SELECT COLUMN_NAME FROM information_schema.columns
WHERE table_schema = 'levee_prioritization'
AND table_name = 'svi2018_us_tract') AS allColumns
WHERE allColumns.COLUMN_NAME NOT IN ('county'))
LEFT JOIN levee_prioritization.justice40_communities b ON (a.fips =
LPAD(round(b.geoid_tract)::text, 11));
You didn't specify the view name for inner select:
CREATE TABLE levee_prioritization.svi_justice_communities_joined AS
SELECT * FROM (SELECT * FROM (SELECT COLUMN_NAME FROM information_schema.columns
WHERE table_schema = 'levee_prioritization'
AND table_name = 'svi2018_us_tract') AS allColumns
WHERE allColumns.COLUMN_NAME NOT IN ('county')) a
LEFT JOIN levee_prioritization.justice40_communities b
ON (a.fips = LPAD(round(b.geoid_tract)::text, 11));

Set value in column guided by result from select. SQL Server

I have a ready select.
SELECT
[c.MySiteRole].[Id],
[c.MySiteRole].[EmployeeId],
[c.MySiteRole].[RoleId],
[c.MySiteRole].[SiteId],
[e.Site].[Id],
[e.Role].[Id],
[e.Role].[Name],
[e.Role].[RoleTypeId]
FROM
[MySiteRole] AS [c.MySiteRole]
INNER JOIN
[Site] AS [e.Site] ON [c.MySiteRole].[SiteId] = [e.Site].[Id]
INNER JOIN
[Role] AS [e.Role] ON [c.MySiteRole].[RoleId] = [e.Role].[Id]
INNER JOIN
(SELECT TOP(1) [c1].[Id]
FROM [Employee] AS [c1]
WHERE [c1].[UserName] = 'MyUserName'
ORDER BY [c1].[Id]) AS [t0] ON [c.MySiteRole].[EmployeeId] = [t0].[Id]
ORDER BY
[t0].[Id], [e.Role].[Id]
In result of this select I have a list.
Next stage I need to compare the result [e.Role].[Id] from select with few other Id and they must be here, not in other table.
"first-guid-id"
"second-guid-id"
"third-guid-id".
If in result select will be coincidence with one of this id I need set for MyColumn update true. !important - coincidence must be only with guid id from this list. For example if coincidence will be with one of them and in result [e.Role].[Id] will be other guid id - need set false for my update column. It's like "isOnlyProgrammerRoles"
Now I have my update script in this case
UPDATE [dbo].[MyTable]
SET [MyColumn] = CAST (CASE WHEN UserName like '%[^0-9]%' then 0 else 1 end AS BIT)
I need to update my script to something like this
UPDATE [dbo].[MyTable]
SELECT [c.MySiteRole].[Id],
[c.MySiteRole].[EmployeeId],
[c.MySiteRole].[RoleId],
[c.MySiteRole].[SiteId],
[e.Site].[Id],
[e.Role].[Id],
[e.Role].[Name],
[e.Role].[RoleTypeId]
FROM [MySiteRole] AS [c.MySiteRole]
INNER JOIN [Site] AS [e.Site]
ON [c.MySiteRole].[SiteId] = [e.Site].[Id]
INNER JOIN [Role] AS [e.Role]
ON [c.MySiteRole].[RoleId] = [e.Role].[Id]
INNER JOIN (SELECT TOP(1) [c1].[Id]
FROM [Employee] AS [c1]
WHERE [c1].[UserName] = 'MyUserName'
ORDER BY [c1].[Id]) AS [t0]
ON [c.MySiteRole].[EmployeeId] = [t0].[Id]
ORDER BY [t0].[Id],
[e.Role].[Id]
Compare the Result.Id with GUID id from list 'guidId', guidId', guidId'
if one or more coincidence from list(only from list + no more guid id in the result){
SET [MyColumn] = 1 like bit
}
Well, this solution doesn't follow the same table aliasing and it removes the unneeded brackets. I'm not sure what you mean by "no guid in the result...". Anyway, something like this
;with three_guid_count_cte(r_id) as (
SELECT
r.Id
FROM
MySiteRole AS msr on
INNER JOIN Site AS s ON msr.SiteId = s.Id
INNER JOIN Role AS r ON msr.RoleId = r.Id
INNER JOIN (SELECT TOP(1) c1.Id
FROM Employee AS c1
WHERE c1.UserName = 'MyUserName'
ORDER BY c1.Id) AS t0 ON msr.EmployeeId = t0.Id
INNER JOIN (values (guid1), (guid2), (guid3)) t(v) on r.Id=t.v
HAVING
COUNT(*)>1;
UPDATE m
SET [MyColumn] = CAST(1 AS BIT)
FROM
[dbo].[MyTable] m
INNER JOIN three_guid_count_cte tgc on m.????=tgc.r_id;

SQL procedure select

I would like to write a procedure to database which will return select all data from database Tournaments plus bool parameter. If user is registered, it will return true.
Call:
exec TournamentsWithLoggedUser #user = 'asd123'
Procedure:
CREATE PROCEDURE [dbo].[TournamentsWithLoggedUser]
#user nvarchar(128)
AS
SELECT
t.Id, t.Info, BIT(r.Id)
FROM
Tournaments AS t
LEFT JOIN
Registrations AS r ON t.Id = r.TournamentId
WHERE
r.UserId IS NULL OR r.UserId = #user
RETURN
it mean something like
1, 'some info', true //1
2, 'some info2', false //2
Why not just use a case statement?
CASE WHEN r.Id IS NULL THEN 0 ELSE 1 END
Change the 0 and 1 to whatever you want for false and true.
SELECT t.Id, t.Info,
-- this works in SQL Server
CAST ((CASE WHEN r.UserId IS NOT NULL THEN 1 ELSE 0 END) AS BIT) AS IsRegistered
FROM Tournaments as t
LEFT JOIN Registrations as r ON t.Id = r.TournamentId
where (r.UserId = '' OR r.UserId = #user)
-- i think this one is help for you...
You are looking for this query
SELECT t.id,
t.info,
Cast (CASE
WHEN r.userid IS NOT NULL THEN 1
ELSE 0
END AS BIT) AS IsRegistered
FROM tournaments AS t
LEFT JOIN registrations AS r
ON t.id = r.tournamentid
AND r.userid = #user
You should clarify what SQL language you are actually using, but an answer can be provided anyway:
CREATE PROCEDURE [dbo].[TournamentsWithLoggedUser]
#user nvarchar(128)
AS
BEGIN
SELECT t.Id, t.Info,
-- this works in SQL Server
CAST ((CASE WHEN r.UserId IS NOT NULL THEN 1 ELSE 0 END) AS BIT) AS IsRegistered
FROM Tournaments as t
LEFT JOIN Registrations as r ON t.Id = r.TournamentId
where r.UserId IS NULL OR r.UserId = #user
-- this should not be required
RETURN
END
However, there is a problem with the logic:
#user is not nullable, so your procedure gives the impression that it looks data for a single user. However, your OR operator allows to select all records from unregistered users united with the record for the particular provided user (if exists).

How can I perform the Count function with a where clause?

I have my database setup to allow a user to "Like" or "Dislike" a post. If it is liked, the column isliked = true, false otherwise (null if nothing.)
The problem is, I am trying to create a view that shows all Posts, and also shows a column with how many 'likes' and 'dislikes' each post has. Here is my SQL; I'm not sure where to go from here. It's been a while since I've worked with SQL and everything I've tried so far has not given me what I want.
Perhaps my DB isn't setup properly for this. Here is the SQL:
Select trippin.AccountData.username, trippin.PostData.posttext,
trippin.CategoryData.categoryname, Count(trippin.LikesDislikesData.liked)
as TimesLiked from trippin.PostData
inner join trippin.AccountData on trippin.PostData.accountid = trippin.AccountData.id
inner join trippin.CategoryData on trippin.CategoryData.id = trippin.PostData.categoryid
full outer join trippin.LikesDislikesData on trippin.LikesDislikesData.postid =
trippin.PostData.id
full outer join trippin.LikesDislikesData likes2 on trippin.LikesDislikesData.accountid =
trippin.AccountData.id
Group By (trippin.AccountData.username), (trippin.PostData.posttext), (trippin.categorydata.categoryname);
Here's my table setup (I've only included relevant columns):
LikesDislikesData
isliked(bit) || accountid(string) || postid(string
PostData
id(string) || posttext || accountid(string)
AccountData
id(string) || username(string)
CategoryData
categoryname(string)
Problem 1: FULL OUTER JOIN versus LEFT OUTER JOIN. Full outer joins are seldom what you want, it means you want all data specified on the "left" and all data specified on the "right", that are matched and unmatched. What you want is all the PostData on the "left" and any matching Likes data on the "right". If some right hand side rows don't match something on the left, then you don't care about it. Almost always work from left to right and join results that are relevant.
Problem 2: table alias. Where ever you alias a table name - such as Likes2 - then every instance of that table within the query needs to use that alias. Straight after you declare the alias Likes2, your join condition refers back to trippin.LikesDislikesData, which is the first instance of the table. Given the second one in joining on a different field I suspect that the postid and accountid are being matched on the same row, therefore it should be AND together, not a separate table instance. EDIT reading your schema closer, it seems this wouldn't be needed at all.
Problem 3: to solve you Counts problem separate them using CASE statements. Count will add the number of non NULL values returned for each CASE. If the likes.liked = 1, then return 1 otherwise return NULL. The NULL will be returned if the columns contains a 0 or a NULL.
SELECT trippin.PostData.Id, trippin.AccountData.username, trippin.PostData.posttext,
trippin.CategoryData.categoryname,
SUM(CASE WHEN likes.liked = 1 THEN 1 ELSE 0 END) as TimesLiked,
SUM(CASE WHEN likes.liked = 0 THEN 1 ELSE 0 END) as TimesDisLiked
FROM trippin.PostData
INNER JOIN trippin.AccountData ON trippin.PostData.accountid = trippin.AccountData.id
INNER JOIN trippin.CategoryData ON trippin.CategoryData.id = trippin.PostData.categoryid
LEFT OUTER JOIN trippin.LikesDislikesData likes ON likes.postid = trippin.PostData.id
-- remove AND likes.accountid = trippin.AccountData.id
GROUP BY trippin.PostData.Id, (trippin.AccountData.username), (trippin.PostData.posttext), (trippin.categorydata.categoryname);
Then "hide" the PostId column in the User Interface.
Instead of selecting Count(trippin.LikesDislikesData.liked) you could put in a select statement:
Select AccountData.username, PostData.posttext, CategoryData.categoryname,
(select Count(*)
from LikesDislikesData as likes2
where likes2.postid = postdata.id
and likes2.liked = 'like' ) as TimesLiked
from PostData
inner join AccountData on PostData.accountid = AccountData.id
inner join CategoryData on CategoryData.id = PostData.categoryid
USE AdventureWorksDW2008R2
GO
SET NOCOUNT ON
GO
/*
Default
*/
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
GO
BEGIN TRAN
IF OBJECT_ID('tempdb.dbo.#LikesDislikesData') IS NOT NULL
BEGIN
DROP TABLE #LikesDislikesData
END
CREATE TABLE #LikesDislikesData(
isLiked bit
,accountid VARCHAR(50)
,postid VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#PostData') IS NOT NULL
BEGIN
DROP TABLE #PostData
END
CREATE TABLE #PostData(
postid INT IDENTITY(1,1) NOT NULL
,accountid VARCHAR(50)
,posttext VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#AccountData') IS NOT NULL
BEGIN
DROP TABLE #AccountData
END
CREATE TABLE #AccountData(
accountid INT
,username VARCHAR(50)
);
IF OBJECT_ID('tempdb.dbo.#CategoryData') IS NOT NULL
BEGIN
DROP TABLE #CategoryData
END
CREATE TABLE #CategoryData(
categoryname VARCHAR(50)
);
INSERT INTO #AccountData VALUES ('1', 'user1')
INSERT INTO #PostData VALUES('1','this is a post')
INSERT INTO #LikesDislikesData (isLiked ,accountid, postid)
SELECT '1', P.accountid, P.postid
FROM #PostData P
WHERE P.posttext = 'this is a post'
SELECT *
FROM #PostData
SELECT *
FROM #LikesDislikesData
SELECT *
FROM #AccountData
SELECT COUNT(L.isLiked) 'Likes'
,P.posttext
,A.username
FROM #PostData P
JOIN #LikesDislikesData L
ON P.accountid = L.accountid
AND L.IsLiked = 1
JOIN #AccountData A
ON P.accountid = A.accountid
GROUP BY P.posttext, A.username
SELECT X.likes, Y.dislikes
FROM (
(SELECT COUNT(isliked)as 'likes', accountid
FROM #LikesDislikesData
WHERE isLiked = 1
GROUP BY accountid
) X
JOIN
(SELECT COUNT(isliked)as 'dislikes', accountid
FROM #LikesDislikesData
WHERE isLiked = 0
GROUP BY accountid) Y
ON x.accountid = y.accountid)
IF (XACT_STATE() = 1 AND ERROR_STATE() = 0)
BEGIN
COMMIT TRAN
END
ELSE IF (##TRANCOUNT > 0)
BEGIN
ROLLBACK TRAN
END
How do you think about the solution? We create a new table SummaryReport(PostID,AccountID,NumberOfLikedTime,NumberOfDislikedTimes).
An user clicks on LIKE or DISLIKE button we update the table. After that, you can query as you desire. Another advantage, the table can be served reporting purpose.

Output Clause: The multi-part identifier could not be bound

I am running in to the dreaded "The multi-part identifier could not be bound" error on a stored procedure I am currently working on. I have a few questions in regards to the query below.
Why am I getting this error?
Why would this error occur on ImportFundingDateTime instead of FloorplanId given that they both come from the same query, but FloorplanId is listed first in the output clause?
Can I adjust this query to not get the error while still keeping the general structure the same?
.
DECLARE #Results Table(
[FloorPlanId] UNIQUEIDENTIFIER,
[ImportFundingDateTime] DATETIME,
[TimeStamp] VARBINARY(8),
[BusinessId] UNIQUEIDENTIFIER
)
UPDATE CacRecord
SET MatchFound = 1
OUTPUT fp.[FloorplanId], cr.[ImportFundingDateTime],
fp.[TimeStamp], buyer.[BusinessId]
INTO #Results( [FloorplanId], [ImportFundingDateTime],
[TimeStamp], [BusinessId])
FROM CacRecord cr WITH (NOLOCK)
INNER JOIN CacBatch cb WITH (NOLOCK)
ON cr.CacBatchId = cb.CacBatchId
INNER JOIN Floorplan fp WITH (NOLOCK)
ON fp.UnitVIN = cr.ImportVin
AND COALESCE(fp.UnitVIN, '') <> ''
INNER JOIN Business buyer WITH (NOLOCK)
ON buyer.BusinessId = fp.BuyerBusinessId
LEFT OUTER JOIN BusinessContact bc WITH (NOLOCK)
ON bc.BusinessId = buyer.BusinessId
LEFT OUTER JOIN Contact c WITH (NOLOCK)
ON c.ContactId = bc.ContactId
WHERE cb.CacJobInstanceId = #cacJobInstanceId
AND fp.FloorplanStatusId = 1 --Approved
AND COALESCE(cr.ImportVin, '') <> ''
AND 1 =
CASE
WHEN cr.ImportFein = buyer.FederalTaxID
AND COALESCE(cr.ImportFein, '') <> '' THEN 1
WHEN cr.ImportSsn = c.Ssn
AND COALESCE(cr.ImportSsn, '') <> '' THEN 1
ELSE 0
END;
Please recheck the syntax of the OUTPUT clause OUTPUT on MSDN
Syntax
<column_name> ::=
{ DELETED | INSERTED | from_table_name } . { * | column_name }
from_table_name
Is a column prefix that specifies a table included in the FROM clause
of a DELETE or UPDATE statement that is used tospecify the rows to
update or delete.
It looks like you have aliased CacRecord in the FROM clause as "cr", but have not correlated that with the UPDATE clause.
Note: Even with it aliases in the FROM clause and NOT aliased in the UPDATE cause, SQL Server appears to recognize CacRecord as the UPDATE table, requiring you to use INSERTED instead of cr as the virtual table name.
UPDATE cr
SET MatchFound = 1
OUTPUT fp.[FloorplanId], INSERTED.[ImportFundingDateTime],
fp.[TimeStamp], buyer.[BusinessId]
INTO #Results( [FloorplanId], [ImportFundingDateTime],
[TimeStamp], [BusinessId])
FROM CacRecord cr WITH (NOLOCK)
INNER JOIN CacBatch cb WITH (NOLOCK)
ON cr.CacBatchId = cb.CacBatchId
INNER JOIN Floorplan fp WITH (NOLOCK)
ON fp.UnitVIN = cr.ImportVin
AND COALESCE(fp.UnitVIN, '') <> ''
INNER JOIN Business buyer WITH (NOLOCK)
ON buyer.BusinessId = fp.BuyerBusinessId
LEFT OUTER JOIN BusinessContact bc WITH (NOLOCK)
ON bc.BusinessId = buyer.BusinessId
LEFT OUTER JOIN Contact c WITH (NOLOCK)
ON c.ContactId = bc.ContactId
WHERE cb.CacJobInstanceId = #cacJobInstanceId
AND fp.FloorplanStatusId = 1 --Approved
AND COALESCE(cr.ImportVin, '') <> ''
AND 1 =
CASE
WHEN cr.ImportFein = buyer.FederalTaxID
AND COALESCE(cr.ImportFein, '') <> '' THEN 1
WHEN cr.ImportSsn = c.Ssn
AND COALESCE(cr.ImportSsn, '') <> '' THEN 1
ELSE 0
END;
For visitors to this question, this code block shows multiple tables being referenced in the OUTPUT clause correctly.
create table TO1 (id int, a int);
create table TO2 (id int, b int);
create table TO3 (id int, c int);
insert into TO1 select 1,1;
insert into TO2 select 1,2;
insert into TO3 select 1,3;
insert into TO3 select 1,4;
declare #catch table (a int, b int, c int)
update c
set c = a.a
output a.a, b.b, INSERTED.c
into #catch(a,b,c)
from TO1 a
inner join TO2 b on a.id=b.id
inner join TO3 c on a.id=c.id