case expression for multiple condition - sql

OriData
+-----------------+-----------+-------+-------+------+
| selected_RowNum | V6_RowNum | SeqNo | Name | IDNo |
+-----------------+-----------+-------+-------+------+
| 1 | 1 | A1234 | Yummy | 1234 |
| 1 | 2 | A1234 | Yummy | 1234 |
| 1 | 3 | A1234 | Yummy | 1234 |
| 1 | 4 | A1234 | Yummy | 1234 |
| 1 | 1 | B123 | Yummy | 1234 | << I want this
| 1 | 1 | C123 | Yummy | 1234 | << I want this
+-----------------+-----------+-------+-------+------+
Result I want
+-----------------+-----------+-------+-------+------+
| selected_RowNum | V6_RowNum | SeqNo | Name | IDNo |
+-----------------+-----------+-------+-------+------+
| 1 | 1 | B123 | Yummy | 1234 |
| 1 | 1 | C123 | Yummy | 1234 |
+-----------------+-----------+-------+-------+------+
Here is my query:
select
case
when selected_rownum=V6_RowNum and V6_RowNum=1 then 'updateonetime'
when selected_rownum=V6_RowNum and V6_RowNum>1 then 'updatemanytimes'
else '0'
end as NewColumnA,
*
from Table #A
I inner join V6 and Selected table and into #A
I want to check any update between 2 tables, so I inner join both table and created rowNum for 2 tables named Selected_rowNum and v6_rownum (that sort by date).
Selected_RowNum = 1 and V6_rowNum = 1 (and this V6_rownum is not repeating for same SeqNo, IDNo)
If I update 1 time, it will triggered in V6 table. If I update many times, it will triggered V6 table many time as you can see in SeqNo=A1234. As you can see, even the IDNo is repeating but it may created many applications. So, it need filter based on IDNo and SeqNo and Selected_RowNum=1 and V6_RowNum=1.
Any idea, how to get the result I want?

From the looks of it, you only want to display the results for rows where there aren't any entries with updates (V6_RowNum > 1 only?).
To do this, you'd need to check that those rows don't exist in the table, like this:
SELECT CASE
WHEN selected_rownum=V6_RowNum and V6_RowNum=1 THEN 'updateonetime'
WHEN selected_rownum=V6_RowNum and V6_RowNum>1 THEN 'updatemanytimes'
ELSE '0'
END as NewColumnA,
*
FROM #A a
WHERE selected_RowNum = 1
AND V6_RowNum = 1
AND NOT EXISTS
(
SELECT 1 FROM #A a2
WHERE a2.SeqNo = a.SeqNo
AND a2.V6_RowNum > 1
)

Please try this.
If select updateonlyone time then
Select selected_RowNum,seqNo,IDNo
,'updateonetime' As OneTime
from #tbl
group by selected_RowNum,seqNo,IDNO
having count(*) = 1
If select updateonlyone and updatemanytimes time then
Select selected_RowNum,seqNo,IDNo
,CASE WHEN Count(*) > 1 THEN 'updatemanytimes' ELSE 'updateonetime' END
from #tbl
group by selected_RowNum,seqNo,IDNO

Related

Replace null values with most recent non-null values SQL

I have a table where each row consists of an ID, date, variable values (eg. var1).
When there is a null value for var1 in a row, I want like to replace the null value with the most recent non-null value before that date for that ID. How can I do this quickly for a very large table?
So presume I start with this table:
+----+------------|-------+
| id |date | var1 |
+----+------------+-------+
| 1 |'01-01-2022'|55 |
| 2 |'01-01-2022'|12 |
| 3 |'01-01-2022'|45 |
| 1 |'01-02-2022'|Null |
| 2 |'01-02-2022'|Null |
| 3 |'01-02-2022'|20 |
| 1 |'01-03-2022'|15 |
| 2 |'01-03-2022'|Null |
| 3 |'01-03-2022'|Null |
| 1 |'01-04-2022'|Null |
| 2 |'01-04-2022'|77 |
+----+------------+-------+
Then I want this
+----+------------|-------+
| id |date | var1 |
+----+------------+-------+
| 1 |'01-01-2022'|55 |
| 2 |'01-01-2022'|12 |
| 3 |'01-01-2022'|45 |
| 1 |'01-02-2022'|55 |
| 2 |'01-02-2022'|12 |
| 3 |'01-02-2022'|20 |
| 1 |'01-03-2022'|15 |
| 2 |'01-03-2022'|12 |
| 3 |'01-03-2022'|20 |
| 1 |'01-04-2022'|15 |
| 2 |'01-04-2022'|77 |
+----+------------+-------+
cte suits perfect here
this snippets returns the rows with values, just an update query and thats all (will update my response).
WITH selectcte AS
(
SELECT * FROM testnulls where var1 is NOT NULL
)
SELECT t1A.id, t1A.date, ISNULL(t1A.var1,t1B.var1) varvalue
FROM selectcte t1A
OUTER APPLY (SELECT TOP 1 *
FROM selectcte
WHERE id = t1A.id AND date < t1A.date
AND var1 IS NOT NULL
ORDER BY id, date DESC) t1B
Here you can dig further about CTEs :
https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver16

How to insert records based on another table value

I have the following three tables:
Permission
| PermissionId | PermissionName |
+--------------+----------------+
| 1 | A |
| 2 | B |
| 3 | C |
| 100 | D |
Group
| GroupId | GroupLevel | GroupName |
+---------+------------+----------------------+
| 1 | 0 | System Administrator |
| 7 | 0 | Test Group 100 |
| 8 | 20 | Test Group 200 |
| 9 | 20 | test |
| 10 | 50 | TestGroup01 |
| 11 | 51 | TestUser02 |
| 12 | 52 | TestUser03 |
GroupPermission
| GroupPermissionId | FkGroupId | FkPermissionId |
+-------------------+-----------+----------------+
| 1 | 1 | 1 |
| 2 | 1 | 2 |
| 3 | 1 | 3 |
| 4 | 1 | 4 |
I need to insert records into GroupPermission table, if table Group, GroupLevel column have 0
then I need to take its GroupId and need to insert values to GroupPermission table as that particular id and 100.
In order to above sample table records, I need to insert the following two records to GroupPermission table,
| FkGroupId | FkPermissionId |
+-----------+----------------+
| 1 | 100 |
| 7 | 100 |
How can I do it
This question is not very clear and I can only assume the value 100 is a static value and that you don't actually have foreign keys as the names of the columns imply. Also, you really should avoid reserved words like "Group" for object names. It makes things more difficult and confusing.
The simple version of your insert might look like this.
insert GroupPermission
(
FkGroupId
, FkPermissionId
)
select g.GroupId
, 100
from [Group] g
where g.GroupLevel = 0
--EDIT--
Since you want to only insert those rows that don't already exist you can use NOT EXISTS like this.
select g.GroupId
, 100
from [Group] g
where g.GroupLevel = 0
AND NOT EXISTS
(
select *
from GroupPermission gp
where gp.FkGroupId = g.GroupId
and g.FkPermissionId = 100
)
Or you could use a left join like this.
select g.GroupId
, 100
from [Group] g
left join GroupPermission gp on gp.FkGroupId = g.GroupId
and gp.FkPermissionId = 100
where g.GroupLevel = 0
and gp.FkGroupId is null

sql: How do I reserve one of the duplicated data with specific condition?

there is a table and some record:
userno | username
-------------------
1 | --this username is null value
1 | a
2 | b
2 | --this username is null value
3 | c
4 | --this username is null value
I want to SELECT this table, and I expect result is:
userno | username
-------------------
1 | a
2 | b
3 | c
4 |
when userno is repetitive, reserve one data with username is not null;
when userno is not repetitive, reserve it.
=========================
=========================
UPDATE1:
there is a table and some record:
No | field1 | flag
----------------------------
1 | | 1
1 | a | 2
1 | b | 3
1 | c | 4
2 | c | 1
2 | e | 2
2 | f | 5
3 | c | 0
4 | |
I want to SELECT this table, and I expect result is:
No | field1 | flag
-------------------
1 | a | 2
2 | e | 2
3 | c | 0
4 | |
when No is repetitive, reserve one data with flag=2;
when No is not repetitive, reserver it.
THIS ANSWERS THE ORIGINAL VERSION OF THE QUESTION.
You can use aggregation:
select userno, max(username) as username
from t
group by userno;
EDIT:
If you have multiple usernames for a given userno and you want all of them:
select userno, username
from t
where username is not null
union all
select userno, max(username)
from t
group by userno
having max(username) is null;

How to get a child table records which exist in results of a table valued function

I have a table named TBL_WorkOrder as below :
+----+------------+----------------+
| Id | SystemCode | WorkOrderTitle |
+----+------------+----------------+
| 1 | C001 | Title 1 |
| 2 | C002 | Title 2 |
| 3 | C003 | Title 3 |
+----+------------+----------------+
and another table named TBL_WorkGroup
+----+---------------+
| Id | WorkGroupName |
+----+---------------+
| 1 | WorkGroup1 |
| 2 | WorkGroup2 |
| 3 | WorkGroup3 |
+----+---------------+
Each work order can contain different work groups as below (TBL_WorkOrderGroup)
+----+-------------+-------------+
| Id | WorkOrderId | WorkGroupId |
+----+-------------+-------------+
| 1 | 1 | 1 |
| 2 | 1 | 3 |
| 3 | 2 | 1 |
+----+-------------+-------------+
The problem is that I send a varchar string like '1,3' to the stored procedure. This varchar is changed to a table using a table valued function. I want to obtain the work orders that contain both '1' and '3' as their work groups.
What should i do in this case?
DECLARE #String VARCHAR(100) = '1,3'
;WITH Split AS
(
SELECT SUBSTRING(#String,0,CHARINDEX(',',#String)) SplitStr,SUBSTRING(#String,CHARINDEX(',',#String)+1,LEN(#String)) RemainStr
UNION ALL
SELECT CASE WHEN CHARINDEX(',',RemainStr) = 0 THEN RemainStr ELSE SUBSTRING(RemainStr,0,CHARINDEX(',',RemainStr)) END,
CASE WHEN CHARINDEX(',',RemainStr) = 0 THEN '' ELSE SUBSTRING(RemainStr,CHARINDEX(',',RemainStr)+1,LEN(RemainStr)) END
FROM Split
WHERE ISNULL(RemainStr,'') <> ''
)
SELECT SplitStr FROM Split

SQL - Splitting a column based on the values

I'm trying to split a column from a result set into 2 columns based on the values from the column.
So a user can subscribe to multiple items and the user can have 2 email addresses which can receive this subscription.
The result set gives a list of subscriptions and their corresponding entries for subscribed email ids.
DB details
Table 1 - user_subscriptions
user_id
email_id - 1 for email id 1 and 2 for email id 2
subscription_id
Table 2 - subscriptions
subscription_id
subscription_name
Now I need all the subscriptions for the user whether subscribed by either of the email ids or not.
So I get a result set something like this
+----------------------+----------+
| subscription_name | email_id |
+----------------------+----------+
| item1 | 1 |
| item1 | 2 |
| item2 | null |
| item3 | 1 |
| item4 | null |
| item5 | 2 |
+----------------------+----------+
So I'm looking to split the above result set into something like below
+-------------------+---------+---------+
| subscription_name | email_1 | email_2 |
+-------------------+---------+---------+
| item1 | 1 or Y | 1 or Y |
| item2 | 0 or N | 0 |
| item3 | 1 | 0 |
| item4 | 0 | 0 |
| item5 | 0 | 1 |
+-------------------+---------+---------+
Hope this question makes sense. Any help would be appreciated!
Updated -----------
Sample Data:
subscriptions -
+-----------------+-------------------+
| subscription_id | subscription_name |
+-----------------+-------------------+
| 1 | item1 |
| 2 | item2 |
| 3 | item3 |
| 4 | item4 |
| 5 | item5 |
+-----------------+-------------------+
user_subscriptions
+---------+----------+-----------------+
| user_id | email_id | subscription_id |
+---------+----------+-----------------+
| 101 | 1 | 1 |
| 101 | 2 | 1 |
| 101 | 1 | 3 |
| 101 | 2 | 5 |
| 102 | 1 | 1 |
| 102 | 2 | 1 |
+---------+----------+-----------------+
Expected Result:
For user_id = 101
+-----------------+-------------------+--------+--------+
| subscription_id | subscription_name | mail_1 | mail_2 |
+-----------------+-------------------+--------+--------+
| 1 | item1 | Y | Y |
| 2 | item2 | N | N |
| 3 | item3 | Y | N |
| 4 | item4 | N | N |
| 5 | item5 | N | Y |
+-----------------+-------------------+--------+--------+
SELECT
S.subscription_id,
S.subscription_name,
CASE
WHEN US1.mail_ID IS NULL THEN 'N'
ELSE 'Y'
END mail_1,
CASE
WHEN US2.mail_ID IS NULL THEN 'N'
ELSE 'Y'
END mail_2
FROM subscriptions S
LEFT JOIN user_subscriptions US1
ON S.subscription_id = US1.subscription_id
AND US1.mail_id = 1
LEFT JOIN user_subscriptions US2
ON S.subscription_id = US2.subscription_id
AND US2.mail_id = 2
WHERE us1.user_id = 5 -- or use a variable #user_ID
OR us2.user_id = 5
You need a conditional aggregate:
select us.subscription_name,
-- there's at least one email
CASE WHEN MIN(us.email_id) IS NOT NULL THEN 'Y' ELSE 'N' END as email_1,
-- there's more than one email
CASE WHEN MIN(us.email_id) <> MAX(us.email_id) THEN 'Y' ELSE 'N' END as email_2
from subscriptions as s
left join user_subscriptions as us
on s.subscription_id = us.subscription_id
where us.user_id = ...
group by us.subscription_name
I've not worked in sybase before, but I'm fairly sure the following SQL will translate easily (or even run directly):
SELECT
s.subscription_name,
COUNT(email_1.subscription_id) AS email_1,
COUNT(email_2.subscription_id) AS email_2
FROM subscriptions AS s
LEFT JOIN user_subscriptions AS email_1 ON (
s.subscription_id = email_1.subscription_id AND
email_1.email_id = 1
)
LEFT JOIN user_subscriptions AS email_2 ON (
s.subscription_id = email_2.subscription_id AND
email_2.email_id = 2
)
;
You could also say IF(email_1.subscription_id IS NOT NULL, 'Y', 'N') etc in the SELECT to return a straight-forward yes/no rather than a count etc.
It works on the principle that the list of LEFT JOIN statements will match any "user subscription" record with email_id=1 and email_id=2 etc.
My lack of sybase knowledge disclaimer: ANSI SQL is can't perform PIVOT - if sybase does, you could do this far more elegantly I'm sure. There's another question+answer which hints that sybase can do such things; it'd be worth your while looking there: https://stackoverflow.com/a/8114446/817132
Hope it helps!