How to change flag value in single query using sql server? - sql-server

I'm having one table, it's containing the column name like flag, that data's are looks like 'Y' or 'N'.
When I'll take a data from that table using "Select Flag from tablename" query means it shows only 'Y' or 'N'.
But what I need is, if it's 'Y' means 'Yes' or 'N' means 'No.
If we will use Stored procedure means we will do this concept easily using 'If' or 'Case' condition.
But I want to take that data using single query.
How can I do this?
Please help me friends...

One way is with a case statement:
select (case when flag = 'Y' then 'Yes'
when flag = 'N' then 'No'
else 'Oops!'
end) as FullFlag
from table t
You can also do this with a calculated column. You could define the table and store the flag as a bit (which is as efficient as possible) and then use a computed column to retrieve another value:
create table . . .
FlagBit bit,
Flag as (case when FlagBit = 1 then 'Yes' else 'No' end)
. . .

Related

create a new column in the table depending from other column

in my table, I got a column where is written the company code
example
DE06 or DE07
now I need to add a new column to this table where will have as value 'YES' for DE06 and 'NO' for DE07
I try to add a condition just for De06 but I cant make it work
ALTER Table dbo.DE06_PROJECT$
add [PROJECT_COMPANY_CODE2] nvarchar(50) null
GO
UPDATE dbo.DE06_PROJECT$ SET [PROJECT_COMPANY_CODE] ='YES' where([COMPANY_CODE]='DE06')
GO
I need a new column [PROJECT_COMPANY_CODE2] with result 'YES' or 'NO' based on the value of the column [COMPANY_CODE]
I forget to mention that in the future I could need 3 possibilities 'YES' for DE06 and 'NO' for DE07 and 'MAYBE" for DE08
If you have SQL Server then you can go for CASE
UPDATE dbo.DE06_PROJECT$
SET [PROJECT_COMPANY_CODE] = CASE WHEN [COMPANY_CODE]='DE06' THEN 'YES' ELSE 'NO' END
Use a computed column to ensure data consistency:
ALTER TABLE dbo.DE06_PROJECT$
ADD [PROJECT_COMPANY_CODE] AS CASE [COMPANY_CODE] WHEN 'DE06' THEN 'YES'
WHEN 'DE07' THEN 'NO'
WHEN 'DE08' THEN 'MAYBE'
ELSE 'whatever' END

Is there a way to restrict user to update column further if it has one of the allowable value

I am looking for a way to restrict user to update a column if it has already a certain value (from allowable value) in SQL Server table.
Say column1 has constrain to allow only one of 'Y' and 'N'
e.g. ([Column1]='N' OR [Column1]='Y')
If the value is 'N' it can be change to 'Y' or 'N'
If the value is 'Y' already then user can not update the column to 'N'
What constraint can be apply to simulate this behavior ?
Is there a way to use check constraint for this or update trigger is the only way (which I am exploring but not sure is that the correct way to achieve this).
You wouldn't be able to do this with a CONSTRAINT, no. A CONSTRAINT "cares" about the value a column is being set to, not what it was. An INSTEAD OF trigger would seem like the better option here.
This is overly simplified, but you could do something like this:
CREATE TRIGGER trg_NoYToN ON dbo.YourTable
INSTEAD OF UPDATE
AS
UPDATE YT
SET SomeColumn = i.SomeColumn,
AnotherColumn = i.AnotherColumn,
YourYNColumn = CASE WHEN YT.YourYNColumn = 'Y' THEN 'Y' ELSE i.YourYNColumn END
...
FROM dbo.YourTable YT
JOIN dbo.inserted i ON YT.YourIDColumn = i.YourIDColumn;
GO
You could, I suppose, also use an AFTER UPDATE trigger to "undo" the change, which would be easier to write, but would require 2 writes on the table for effected rows:
CREATE TRIGGER trg_StopYtoN ON dbo.YourTable
AFTER UPDATE
AS
UPDATE YT
SET YourYNColumn = 'Y'
FROM dbo.YourTable YT
JOIN deleted d ON YT.YourIDColumn = d.YourIDColumn
WHERE d.YourYNColumn = 'Y'
AND YT.YourYNColumn = 'N';
GO

Update a view doesn't work

I'm working on a view which is then updated by the user. This update basically changes the value of column. But right now it doesnt let me do that and produces this :
Update or insert of view or function '' failed because it contains a derived or constant field.
I know this is because I have a constant in the select statement but is there a way to get around it? Please help
This is my code for the view
Create view Schema.View1
as
SELECT
Convert(Varchar(20),l.jtpName) as JobType, Convert(Varchar(10),' <All> ')as SubCategory , Convert(varchar (3), Case when a.jtpName= l.jtpName and a.subName= ' <All> ' then 'Yes' else 'No' end) As AutoProcess from Schema.JobType l left join Schema.Table1 a on l.jtpName=a.jtpName
UNION
SELECT
Convert(Varchar(20),a.jtpName) as JobType, Convert(Varchar(10),a.subName) as SubCategory, Convert(varchar (3),Case when b.jtpName= a.jtpName and b.subName= a.subName then 'Yes' else 'No' end) As AutoProcess from Schema.SubCategory a left join fds.Table1 b on a.subName=b.subName
GO
Finally the update statement:
UPDATE Schema.View1 SET AUTOPROCESS = Case WHEN AUTOPROCESS = 'Yes' Then 'No' END Where JOBTYPE = 'Transport' and SUBCATEGORY= 'Cargo'
Thank You
You cannot update a column that is the result of a computation.
According to MSDN, one of the conditions for a view column to be updatable is this:
Any modifications, including UPDATE, INSERT, and DELETE statements, must reference columns from only one base table.
The columns being modified in the view must directly reference the underlying data in the table columns. The columns cannot be derived in any other way, such as through the following:
An aggregate function: AVG, COUNT, SUM, MIN, MAX, GROUPING, STDEV, STDEVP, VAR, and VARP.
A computation. The column cannot be computed from an expression that uses other columns. Columns that are formed by using the set operators UNION, UNION ALL, CROSSJOIN, EXCEPT, and INTERSECT amount to a computation and are also not updatable.
The columns being modified are not affected by GROUP BY, HAVING, or DISTINCT clauses.
TOP is not used anywhere in the select_statement of the view together with the WITH CHECK OPTION clause.
Here not only does your view uses the UNION statement, the AutoProcess field you are trying to update is actually the result of a CASE statement that uses two fields. It makes no sense to try and update that.
I would recommend that you use stored proc to perform writing operations. Or, as Damien suggest, you could use an INSTEAD OF trigger on the view too.
You have to create a TRIGGER and manually apply the changes from the inserted and deleted pseudo-tables against the base tables yourself.
There is no way for sql server to work backwards from your convert functions to the original fields. You cannot update a view this way.
If the view contained your jptName and subName fields, you might be able to update just those fields.

SQL Server Update with complex logic

I have a table which I need to update to value of Y, but this update is based upon some results from other tables, and I am not sure how to do this.
Basically, I need to complete the following checks
I need to check from the table I need to update that the other table has exactly 19 matching rows
In those matching rows that one of the fields is not null
I have two other tables which I need to check that records exist in the latter table plus to ensure that the matching records in the latter do not contain the value of "Y" in one of the fields.
My approach to this is to use UNIONs, but I would like someone to advise me whether this approach is correct or whether there is a much better way of doing it:
SELECT '1'
FROM t_A_Outbound
Where NOT HEADER IN (Select HEADER FROM t_B_Outbound)
UNION
SELECT '1'
FROM t_A_Outbound
Where HEADER IN (Select HEADER FROM t_B_Outbound
WHERE NOT INCOMPLETE ='Y')
UNION
Select '1'
From t_C_Outbound
Where ValueString = ''
UNION
Select '1'
From t_C_Outbound
WHERE Exists(Select Count(key), HEADER
From t_C_Outbound IN (SELECT HEADER FROM table_that_needs_updating)
Group By HEADER
Having NOT Count(Cast(key as Int)) = 19)
I thought of using 1 as flag to say if this value comes back to update the field in the table I need to change.
Can anyone advise me?
It is rather unclear to me what unions do for you.
You want an update statement something like:
update table
set y = . . .
where header in (Select header
From t_C_Outbound
Group By HEADER
Having Count(*)= 19 and
count(KEY) = count(*)
) and
header in (select header
from other table
group by header
having sum(case when col = 'Y' then 1 else 0 end) = 0
)
and so on. You don't describe the problem clearly enough to give more detailed code.

How to select true/false based on column value?

I have a table with the following columns:
EntityId, EntityName, EntityProfile, .................
I want to select the Id and Name and true/false column based on the value of entity profile,
for example a returned result set like below, would mean that entities 1&2 have profiles while 3 not.
1 Name1 True
2 Name2 True
3 Name3 False
etc.....
I know I can do it using a function that return true/false based on the profile value like this:
SELECT EntityId, EntityName, dbo.EntityHasProfile(EntityId) AS HasProfile FROM Entities
but I'm returning a large no. of records and with this function call for each record, the query is very slow, and when I remove the function call the query execution time drops significantly.
So is there another way of doing this?
Thanks
Use a CASE. I would post the specific code, but need more information than is supplied in the post - such as the data type of EntityProfile and what is usually stored in it. Something like:
CASE WHEN EntityProfile IS NULL THEN 'False' ELSE 'True' END
Edit - the entire SELECT statement, as per the info in the comments:
SELECT EntityID, EntityName,
CASE WHEN EntityProfile IS NULL THEN 'False' ELSE 'True' END AS HasProfile
FROM Entity
No LEFT JOIN necessary in this case...
You can try something like
SELECT e.EntityId,
e.EntityName,
CASE
WHEN ep.EntityId IS NULL THEN 'False'
ELSE 'TRUE'
END AS HasProfile
FROM Entities e LEFT JOIN
EntityProfiles ep ON e.EntityID = ep.EntityID
Or
SELECT e.EntityId,
e.EntityName,
CASE
WHEN e.EntityProfile IS NULL THEN 'False'
ELSE 'TRUE'
END AS HasProfile
FROM Entities e
Maybe too late, but I'd cast 0/1 as bit to make the datatype eventually becomes True/False when consumed by .NET framework:
SELECT EntityId,
EntityName,
CASE
WHEN EntityProfileIs IS NULL
THEN CAST(0 as bit)
ELSE CAST(1 as bit) END AS HasProfile
FROM Entities
LEFT JOIN EntityProfiles ON EntityProfiles.EntityId = Entities.EntityId`
If the way you determine whether or not an entity has a profile is a deterministic function, and doesn't require any access to another table, you could write a stored function and define a computed, persisted field which would store that value for you and not have to re-compute it over and over again.
If you need to query a separate table (to e.g. check the existance of a row), you could still make this "HasProfile" a column in your entity table and just compute that field on a regular basis, e.g. every night or so. If you have the value stored as an atomic value, you don't need the computation every time. This works as long as that fact - has a profile or not - doesn't change too frequently.
To add a column to check whether or not EntityProfile is empty, do something like this:
CREATE FUNCTION CheckHasProfile(#Field VARCHAR(MAX))
RETURNS BIT
WITH SCHEMABINDING
AS BEGIN
DECLARE #Result BIT
IF #Field IS NULL OR LEN(#Field) <= 0
SET #Result = 0
ELSE
SET #Result = 1
RETURN #Result
END
and then add a new computed column to your table Entity:
ALTER TABLE dbo.Entity
ADD HasProfile AS dbo.CheckHasProfile(EntityProfile) PERSISTED
Now you have a BIT column and it's persisted, e.g. doesn't get computed every time to access the row, and should perform just fine!
At least in Postgres you can use the following statement:
SELECT EntityID, EntityName, EntityProfile IS NOT NULL AS HasProfile FROM Entity
What does the UDF EntityHasProfile() do?
Typically you could do something like this with a LEFT JOIN:
SELECT EntityId, EntityName, CASE WHEN EntityProfileIs IS NULL THEN 0 ELSE 1 END AS Has Profile
FROM Entities
LEFT JOIN EntityProfiles
ON EntityProfiles.EntityId = Entities.EntityId
This should eliminate a need for a costly scalar UDF call - in my experience, scalar UDFs should be a last resort for most database design problems in SQL Server - they are simply not good performers.

Resources