I am deriving a CTE using data from 2 tables, and I have a requirement to update 2 columns in this CTE. The I can use UPADTE CTE and then a case statement to update one column, but the second one.
for example
update cte
set col1 = case when thisrecord = thatrecord then 1 else 0 end
col2 = case max(thisrecord) = max(thatrecord) then 1 else 0 end
It gives me error.
If I use
update cte
set col1, set col2
from cte
where this = that
then it says cte is not updatable as it has multiple base tables.
How to solve this puzzle, does anyone has a similar scenario or possible work out?
Related
Using select and case statement in SQL
How to make the 4th column "1" if next row of LETTER column is D. See example below:
https://i.stack.imgur.com/br4dn.png
You can combine CASE with LEAD(). Assuming you are ordering by stepthe query can look like:
select
t.*,m
case when lead(letter) over(order by step) = 'D'
then 1 else 0 end as is_next_row_letter_d
from t
Assuming that the STEP column provides the ordering and that it is continuous, we could use a self-join approach here:
SELECT t1.STEP, t1.ID, t1.LETTER,
CASE WHEN t2.LETTER = 'D' THEN 1 ELSE 0 END AS IS_NEXT_D
FROM yourTable t1
LEFT JOIN yourTable t2
ON t2.STEP = t1.STEP + 1
ORDER BY t1.STEP;
I am quite new to SQL. Playing around with it and got stuck in the following scenario.
I have a table with the following data
My requirement is, in the FirstCol column, it has '11121' 3 times, and SecondCol has 1001 two times against FirstCol and it has 1002 against the same '11121' value which should not be. If it exists that way, I need to find all the data in such scenarios and need to display a column beside these two columns with a flag value indicating 1 if the value in the SecondCol is different than the other values. '0' should be displayed for the remaining.
I tried using group by, dense_rank() but couldn't get the desired results. Someone please help me out in getting the desired result for this.
I think you want:
select t.*,
(case when min(col1) over (partition by col2) =
max(col1) over (partition by col2)
then 0 else 1
end) as flag
from t;
This flags all rows where col2 has multiple values in col1.
You can use EXISTS and a correlated subquery, that checks, if there are row with the same firstcol but with a different secondcol. Put that in a CASE returning 1 if such a record exists, 0 otherwise.
SELECT t1.firstcol,
t1.secondcol,
CASE
WHEN EXISTS (SELECT *
FROM elbat t2
WHERE t2.firstcol = t1.firstcol
AND t2.secondcol <> t1.secondcol) THEN
1
ELSE
0
END flag
FROM elbat t1;
I I have one tables updating two columns if the second column the update more or equal to 4 set the other column to 0
Tried case statement .... but still not working please help!
update [dbo].[QueuedSms_TEST]
set issent = 0,pendingstatusid = pendingstatusid + 1
where sendresponse is null
while (select pendingstatusid from [dbo].[QueuedSms_TEST]) > 3
update [dbo].[QueuedSms_TEST]
set issent = -1
First you create a temporal query to get a row_number, and then update that with the required rules.
SQL Demo
WITH cte as (
SELECT *,
ROW_NUMBER() OVER (ORDER BY pendingstatusid) as rn
FROM QueuedSms_TEST
)
UPDATE cte
SET pendingstatusid = rn,
issent = CASE WHEN rn > 3
THEN -1
ELSE 0
END;
I have the following query. I simplified it for demo purpose. I am using SQL Server - t-sql
Select tm.LocID = (select LocID from tblLoc tl
where tl.LocID = tm.LodID )
from tblMain tm
if the subquery returns multiple records, I like to assign tm.LocID to null else if there is only 1 record returned then assign it to tm.LocID. I am looking for a simple way to do this. Any help would be appreciated.
One way I can see is to have a CASE statement and check if (Count * > 1 ) then assign null else return the value but that would require a select statement within a select statement.
You have the right idea about using a case expression for count(*), but it will not require another subquery:
SELECT tm.LocID = (SELECT CASE COUNT(*) WHEN 1 THEN MAX(LocID) END
FROM tblLoc tl
WHERE tl.LocID = tm.LodID )
FROM tblMain tm
or just use a HAVING clause, like
Select tm.LocID = (select LocID from tblLoc tl
where tl.LocID = tm.LodID
group by locID
having count(*) = 1)
)
from tblMain tm
Your query above (and many of the other answers here) is a correlated subquery which will be very slow since it performs a separate aggregation query on each record. This following will address both your problem and potentially perform a bit better since the count happens in a single pass.
SELECT
CASE
WHEN x.locid IS NOT NULL THEN x.locid
ELSE NULL
END
FROM tblMain m
LEFT JOIN (
SELECT
locid
FROM tblLoc
GROUP BY locid
HAVING COUNT(1) = 1
) x
ON x.locid = m.locid
;
The above is in Postgres syntax (what I'm familiar with) so you would have to make it TSQL compatible.
I'm trying to create a query that would generate a cross-check table with about 40 custom columns that show Y or N. Right now I have
SELECT DISTINCT [Company],
[Option1],
[Option2],
[Option3],
CASE
WHEN [Table1].[ID1] IN (SELECT ID2 FROM Table2 WHERE Variable = 1 AND Bit = 1) THEN
'Y'
ELSE 'N'
END AS 'CustomColumn1:',
CASE
WHEN [Table1].[ID1] IN (SELECT ID2 FROM Table2 WHERE Variable = 2 AND Bit = 1) THEN
'Y'
ELSE 'N'
END AS 'CustomColumn1:',
CASE
WHEN [Table1].[ID1] IN (SELECT ID2 FROM Table2 WHERE Variable = 3 AND Bit = 1) THEN
'Y'
ELSE 'N'
END AS 'CustomColumn1:',
.............
-- REPEAT ANOTHER 40 times
FROM [Table1]
WHERE [Table1].[OtherCondition] = 'True'
ORDER BY [Company]
So my question is, how do I create a loop (while? for?) that will loop on variable and assign Y or N to the row based on the condition, rather than creating 40+ Case statements?
You couldn't use a loop, but you could create a stored procedure/function to perform the sub-select and case expression and call that 40 times.
Also, you could improve performance of the sub-select by changing it to
SELECT 1 FROM Table2 WHERE EXISTS [Table2].[ID2] = [Table1.ID1] AND Variable = 3 AND Bit = 1
A loop (that is, iterating through a cursor) works on rows, not columns. You will still have to have 40 expressions, one for each column, and the performance will be terrible.
Let SQL Server do its job. And do your bit by telling exactly what you need and creating proper indices. That is, replace
CASE WHEN [Table1].[ID1] IN (SELECT ID2 FROM Table2 WHERE Variable = 2 AND Bit = 1)
with
CASE WHEN EXISTS (SELECT 0 FROM Table2 WHERE ID2 = [Table1].[ID1] AND Variable = 2 AND Bit = 1)
If the output is so vastly different than the schema, there is a question as to whether the schema properly models the business requirements. That said, I would recommend just writing the SQL. You can simplify the SQL like so:
Select Company
, Option1, Option2, Option3
, Case When T2.Variable = 1 Then 'Y' Else 'N' End As CustomCol1
, Case When T2.Variable = 2 Then 'Y' Else 'N' End As CustomCol2
, Case When T2.Variable = 3 Then 'Y' Else 'N' End As CustomCol3
, Case When T2.Variable = 4 Then 'Y' Else 'N' End As CustomCol4
...
From Table1 As T1
Left Join Table2 As T2
On T2.ID2 = T1.ID
And T2.Bit = 1
Where T1.OtherCondition = 'True'
Group By T1.Company
Order By T1.Company
If you want to write something that can help you auto-gen those Case statements (and you are using SQL Server 2005+), you could do something like:
With Numbers As
(
Select 0 As Value
Union All
Select Value + 1
From Numbers
Where Value < 41
)
Select ', Case When T2.Variable = ' + Cast(N.Value As varchar(10)) + ' Then ''Y'' Else ''N'' End As CustomCol' + Cast(N.Value As varchar(10))
From Numbers As N
You would run the query and copy and paste the results into your procedure or code.
One way could have been to use Pivot statement, which is in MS SQL 2005+. But even in that you have to put 1 ... 40 hardcoded columns in pivot statement.
Other way i can think of is to create dynamic SQL, but it is not so much recommended, So what we can do is we can create a dynamic sql query by running a while loop on table and can create the big sql and then we can execute it by using sp_execute. So steps would be.
int #loopVar
SET #loopVar = 0
int #rowCount
varchar #SQL
SET #SQl = ''
Select #rowcount = Count(ID2) from Table2
WHILE(#loopVar <= #rowCount)
BEGIN
// create ur SQL here
END
sp_execute(#SQL)