SQL Server query to retrieve all from View - sql-server

I have a SQL View, similiar to the one below:
map_id | type_id | path
1 1 0
2 2 0
3 3 0
4 1 A>B
5 1 A>B>C
6 2 T>Z
7 2 T>Z>X
8 3 U
9 3 X>Y
10 1 D
And another table, tblRoles
role_group_id | type_id | map_id
1 1 1
2 1 4
I want to build a query that will include all map_id where role_group_id has the map_id = 1 and for the rest it should only get the corresponding map_id
So, the query result should look like:
role_group_id | type_id | map_id | path
1 1 4 A>B
1 1 5 A>B>C
1 1 10 D
1 1 1 0
2 1 4 A>B
Could someone point me to the correct way?
Thank you!

Haven't tested this yet, I hope this should work.
SELECT r.role_group_id
,r.type_id
,sv.map_id
,sv.path
FROM tblRoles r
LEFT JOIN sampleView sv ON r.type_id = sv.type_id
WHERE r.map_id = 1
UNION
SELECT r.role_group_id
,r.type_id
,r.map_id
,sv.path
FROM tblRoles r
INNER JOIN sampleView sv ON r.map_id = sv.map_id
WHERE r.map_id <> 1

You can use UNION
#rosuandreimihai: select all when map_id=1 and if map_id is different, select only the
corresponding row
DECLARE #CurrentMapId INT = 1
SELECT * FROM FirstTable
WHERE
TYPE_ID IN
(
SELECT r.type_id FROM tblRoles r
WHERE
map_id = #CurrentMapId
)
UNION
SELECT * FROM FirstTable
WHERE
map_id IN
(
SELECT r.map_id FROM tblRoles r
WHERE
#CurrentMapId = 1 OR
map_id = #CurrentMapId
)

Related

Select data from previous rows with condition

My data looks like this
col1; col2; col3; col4; sort; desc; levels
1 1 1 1 10 ab null
1 1 1 2 20 c 1
1 1 1 3 30 d null
1 1 1 4 40 e null
1 1 1 5 50 fg 1
1 1 1 6 60 hij 1
1 1 1 7 70 k 1
The desired output looks like this
col1; col2; col3; col4; desc; addDesc
1 1 1 1 ab null
1 1 1 2 c ab
1 1 1 3 d null
1 1 1 4 e null
1 1 1 5 fg e
1 1 1 6 hij e
1 1 1 7 k e
The logic is whenever the column LEVELS is not null, take the value from previous DESC where LEVELS is null.
I hope you guys understand this!
Thank you all in advance!
You can use OUTER APPLY:
SELECT t1.col1,
t1.col2,
t1.col3,
t1.col4,
t1.[desc],
CASE
WHEN t1.levels IS NOT NULL THEN t2.[desc]
END [addDesc]
FROM dbo.YourTable t1
OUTER APPLY (SELECT TOP 1 [desc]
FROM dbo.YourTable
WHERE levels IS NULL
AND sort < t1.sort
ORDER BY sort DESC) t2;

SQL Server - build up query using table valued function

I have the following tables structure:
tblMapping
map_id | name | parent_id
1 A 0
2 B 1
3 C 2
4 D 2
5 E 4
tblEditableContent
id | map_id | desc_id | isExcluded
1 1 0 0
2 4 0 1
In this table, tblEditableContent, desc_id=0 means that all elements below the given map_id (all its children) are allowed to be displayed and desc_id=1 means that the node itself is selected.
I also have a table valued function (mapping) that will build up the node for a given map_id, similar to the result below:
for select * from dbo.mapping(1)
map_id | name
1 A
2 B
3 C
4 D
5 E
for select * from dbo.mapping(4)
map_id | name
4 D
5 E
Now, for the task and requirement.
I try to create the following result:
map_id | name | desc_id | isExcluded
1 A 0 0
2 B 0 0
3 C 0 0
In the same time, if we change the value of desc_id in tblEditableContent from 0 to 1, then the output should be:
map_id | name | desc_id | isExcluded
1 A 0 0
2 B 0 0
3 C 0 0
5 E 0 0
And here is what I have tried out until now:
select ca.map_id, ca.name, ec.desc_id, ec.isExcluded from tblEditableContent ec
CROSS APPLY (
Select * From dbo.mapping(ec.map_id)
) ca
where ec.isExcluded = 0
order by ca.map_id
You can try a query like below:
select
ec.*
from tblEditableContent ec
join
(
select
ca.map_id as map_id,
MAX(ec.isExcluded) as isExcluded
from tblEditableContent ec
OUTER APPLY
(
Select map_id from dbo.mapping(ec.map_id) where ec.desc_id =0 or (ec.desc_id =1 and map_id=ec.map_id)
) ca
group by ca.map_id
)ca
on ca.isExcluded=0 and ec.map_id=ca.map_id

How to count number of months in T-SQL

I've got a problem in SQL Server.
"Whate'er is well conceived is clearly said, And the words to say it flow with ease", Nicolas Boileau-Despreaux
Well, I don't think I'll be able to make it clear but I'll try ! And I'd like to apologize for my bad english !
I've got this table :
id ind lvl result date
1 1 a 3 2017-01-31
2 1 a 3 2017-02-28
3 1 a 1 2017-03-31
4 1 a 1 2017-04-30
5 1 a 1 2017-05-31
6 1 b 1 2017-01-31
7 1 b 3 2017-02-28
8 1 b 3 2017-03-31
9 1 b 1 2017-04-30
10 1 b 1 2017-05-31
11 2 a 3 2017-01-31
12 2 a 1 2017-02-28
13 2 a 3 2017-03-31
14 2 a 1 2017-04-30
15 2 a 3 2017-05-31
I'd like to count the number of month the combo {ind, lvl} remain in the result 1 before re-initializing the number of month to 0 if the result is not 1.
Clearly, I need to get something like that :
id ind lvl result date BadResultRemainsFor%Months
1 1 a 3 2017-01-31 0
2 1 a 3 2017-02-28 0
3 1 a 1 2017-03-31 1
4 1 a 1 2017-04-30 2
5 1 a 1 2017-05-31 3
6 1 b 1 2017-01-31 1
7 1 b 3 2017-02-28 0
8 1 b 3 2017-03-31 0
9 1 b 1 2017-04-30 1
10 1 b 1 2017-05-31 2
11 2 a 3 2017-01-31 0
12 2 a 1 2017-02-28 1
13 2 a 3 2017-03-31 0
14 2 a 1 2017-04-30 1
15 2 a 3 2017-05-31 0
So that if I was looking for the number of months the result was 1 for the date 2017-05-31 with the id 1 and the lvl a, I know it's been 3 months.
Assume all the date the the end day of month:
;WITH tb(id,ind,lvl,result,date) AS(
select 1,1,'a',3,'2017-01-31' UNION
select 2,1,'a',3,'2017-02-28' UNION
select 3,1,'a',1,'2017-03-31' UNION
select 4,1,'a',1,'2017-04-30' UNION
select 5,1,'a',1,'2017-05-31' UNION
select 6,1,'b',1,'2017-01-31' UNION
select 7,1,'b',3,'2017-02-28' UNION
select 8,1,'b',3,'2017-03-31' UNION
select 9,1,'b',1,'2017-04-30' UNION
select 10,1,'b',1,'2017-05-31' UNION
select 11,2,'a',3,'2017-01-31' UNION
select 12,2,'a',1,'2017-02-28' UNION
select 13,2,'a',3,'2017-03-31' UNION
select 14,2,'a',1,'2017-04-30' UNION
select 15,2,'a',3,'2017-05-31'
)
SELECT t.id,t.ind,t.lvl,t.result,t.date
,CASE WHEN t.isMatched=1 THEN ROW_NUMBER()OVER(PARTITION BY t.ind,t.lvl,t.id-t.rn ORDER BY t.id) ELSE 0 END
FROM (
SELECT t1.*,c.MonthDiff,CASE WHEN c.MonthDiff=t1.result THEN 1 ELSE 0 END AS isMatched
,CASE WHEN c.MonthDiff=t1.result THEN ROW_NUMBER()OVER(PARTITION BY t1.ind,t1.lvl,CASE WHEN c.MonthDiff=t1.result THEN 1 ELSE 0 END ORDER BY t1.id) ELSE null END AS rn
FROM tb AS t1
LEFT JOIN tb AS t2 ON t1.ind=t2.ind AND t1.lvl=t2.lvl AND t2.id=t1.id-1
CROSS APPLY(VALUES(ISNULL(DATEDIFF(MONTH,t2.date,t1.date),1))) c(MonthDiff)
) AS t
ORDER BY t.id
id ind lvl result date
----------- ----------- ---- ----------- ---------- --------------------
1 1 a 3 2017-01-31 0
2 1 a 3 2017-02-28 0
3 1 a 1 2017-03-31 1
4 1 a 1 2017-04-30 2
5 1 a 1 2017-05-31 3
6 1 b 1 2017-01-31 1
7 1 b 3 2017-02-28 0
8 1 b 3 2017-03-31 0
9 1 b 1 2017-04-30 1
10 1 b 1 2017-05-31 2
11 2 a 3 2017-01-31 0
12 2 a 1 2017-02-28 1
13 2 a 3 2017-03-31 0
14 2 a 1 2017-04-30 1
15 2 a 3 2017-05-31 0
By slightly tweaking your input data and slightly tweaking how we define the requirement, it becomes quite simple to produce the expected results.
First, we tweak your date values so that the only thing that varies is the month and year - the days are all the same. I've chosen to do that my adding 1 day to each value1. The fact that this produces results which are one month advanced doesn't matter here, since all values are similarly transformed, and so the monthly relationships stay the same.
Then, we introduce a numbers table - here, I've assumed a small fixed table is adequate. If it doesn't fit your needs, you can easily locate examples online for creating a large fixed numbers table that you can use for this query.
And, finally, we recast the problem statement. Instead of trying to count months, we instead ask "what's the smallest number of months, greater of equal to zero, that I need to go back from the current row, to locate a row with a non-1 result?". And so, we produce this query:
declare #t table (id int not null,ind int not null,lvl varchar(13) not null,
result int not null,date date not null)
insert into #t(id,ind,lvl,result,date) values
(1 ,1,'a',3,'20170131'), (2 ,1,'a',3,'20170228'), (3 ,1,'a',1,'20170331'),
(4 ,1,'a',1,'20170430'), (5 ,1,'a',1,'20170531'), (6 ,1,'b',1,'20170131'),
(7 ,1,'b',3,'20170228'), (8 ,1,'b',3,'20170331'), (9 ,1,'b',1,'20170430'),
(10,1,'b',1,'20170531'), (11,2,'a',3,'20170131'), (12,2,'a',1,'20170228'),
(13,2,'a',3,'20170331'), (14,2,'a',1,'20170430'), (15,2,'a',3,'20170531')
;With Tweaked as (
select
*,
DATEADD(day,1,date) as dp1d
from
#t
), Numbers(n) as (
select 0 union all select 1 union all select 2 union all select 3 union all select 4
union all
select 5 union all select 6 union all select 7 union all select 8 union all select 9
)
select
id, ind, lvl, result, date,
COALESCE(
(select MIN(n) from Numbers n1
inner join Tweaked t2
on
t2.ind = t1.ind and
t2.lvl = t1.lvl and
t2.dp1d = DATEADD(month,-n,t1.dp1d)
where
t2.result != 1
),
1) as [BadResultRemainsFor%Months]
from
Tweaked t1
The COALESCE is just there to deal with the edge case, such as for your 1,b data, where there is no previous row with a non-1 result.
Results:
id ind lvl result date BadResultRemainsFor%Months
----------- ----------- ------------- ----------- ---------- --------------------------
1 1 a 3 2017-01-31 0
2 1 a 3 2017-02-28 0
3 1 a 1 2017-03-31 1
4 1 a 1 2017-04-30 2
5 1 a 1 2017-05-31 3
6 1 b 1 2017-01-31 1
7 1 b 3 2017-02-28 0
8 1 b 3 2017-03-31 0
9 1 b 1 2017-04-30 1
10 1 b 1 2017-05-31 2
11 2 a 3 2017-01-31 0
12 2 a 1 2017-02-28 1
13 2 a 3 2017-03-31 0
14 2 a 1 2017-04-30 1
15 2 a 3 2017-05-31 0
1An alternative way to perform the adjustment is to use a DATEADD/DATEDIFF pair to perform a "floor" operation against the dates:
DATEADD(month,DATEDIFF(month,0,date),0) as dp1d
Which resets all of the date values to be the first of their own month rather than the following month. This may fell more "natural" to you, or you may already have such values available in your original data.
Assuming the dates are continously increasing in month, you can use window function like so:
select
t.id, ind, lvl, result, dat,
case when result = 1 then row_number() over (partition by grp order by id) else 0 end x
from (
select t.*,
dense_rank() over (order by e, result) grp
from (
select
t.*,
row_number() over (order by id) - row_number() over (partition by ind, lvl, result order by id) e
from your_table t
order by id) t ) t;

How to transpose rows to columns in SQL Server

I have a fact table as below:
Table Types
TypeId | Name
1 x
2 y
3 z
Table Period:
PeriodId | Date
1 2014-01-31
2 2015-01-31
RowNumber | Value | TypeId | Identifier | PeriodId
1 12 1 cc1 1
2 10 2 cc1 2
3 17 3 cc1 1
.. 30 ... ... ..
.. 60 1 cc2 1
23 2 cc2 2
From these tables I am trying to create a single flatten table as below:
Identifier | periodId | x | y | z
cc1 1 12 10 17
cc1 2 .. .. ..
cc2 1 .. .. ..
How can I query to get the data in the above format?
INSERT INTO NewTable
SELECT Identifier, PeriodId,
(SELECT Value FROM [Values] v2 WHERE v2.Identifier = v1.Identifier AND v2.PeriodId = v1.PeriodId AND v2.TypeId = 1) AS 'x',
(SELECT Value FROM [Values] v2 WHERE v2.Identifier = v1.Identifier AND v2.PeriodId = v1.PeriodId AND v2.TypeId = 2) AS 'y',
(SELECT Value FROM [Values] v2 WHERE v2.Identifier = v1.Identifier AND v2.PeriodId = v1.PeriodId AND v2.TypeId = 3) AS 'z'
FROM [Values] v1
GROUP BY Identifier, PeriodId
Is this what you need?

Count and Group By for products sold

I have a table Transaction & a table product as below .
Each Transaction has multiple products.
ProductId Name
1 ABC
2 DEF
3 GHI
Each transaction can have multiple products sold.
TransactionId ProductSoldInDept1 ProductSoldinDept2 ProductSoldinDept3
1 1 null null
2 1 2 null
3 3 1 null
4 2 3 1
I am planning to generate a report and I would like to get a result something like this :
This shows the number of products sold per each department grouped by Id
Expected Result :
ProductID Department1ProdCount Department2ProdCount Department3ProdCount
1 2 1 1
2 1 1 0
3 1 1 0
I could get till here , this is a query to get the counts for one specific product
which is productid : 1
I would like to know how I could use a group by here :
select Count(CASE WHEN ProductSoldInDept1 = 1 THEN 1 END) ,
Count(CASE WHEN ProductSoldInDept2 = 1 THEN 1 END) ,
Count(CASE WHEN ProductSoldInDept3 = 1 THEN 1 END)
from Table1
SELECT
p.ProductID,
Dept1ProdCount = COUNT(CASE WHEN t.ProductSoldInDept1 = p.ProductID THEN 1 END),
Dept2ProdCount = COUNT(CASE WHEN t.ProductSoldInDept2 = p.ProductID THEN 1 END),
Dept3ProdCount = COUNT(CASE WHEN t.ProductSoldInDept3 = p.ProductID THEN 1 END)
FROM dbo.Product AS p
LEFT OUTER JOIN dbo.[Transaction] AS t
ON p.ProductID IN
(t.ProductSoldInDept1, t.ProductSoldinDept2, t.ProductSoldinDept3)
GROUP BY p.ProductID;
Result
| PRODUCTID | DEPT1PRODCOUNT | DEPT2PRODCOUNT | DEPT3PRODCOUNT |
----------------------------------------------------------------
| 1 | 2 | 1 | 1 |
| 2 | 1 | 1 | 0 |
| 3 | 1 | 1 | 0 |
See a demo
Try this
select ProductID,
v.Department1ProdCount, v.Department2ProdCount, v.Department3ProdCount
from product a
cross apply
(
select Count(CASE WHEN ProductSoldInDept1 = a.ProductID THEN 1 END) Department1ProdCount,
Count(CASE WHEN ProductSoldInDept2 = a.ProductID THEN 1 END) Department2ProdCount,
Count(CASE WHEN ProductSoldInDept3 = a.ProductID THEN 1 END) Department3ProdCount
from Table1
) v
This:
TransactionId ProductSoldInDept1 ProductSoldinDept2 ProductSoldinDept3
1 1 null null
2 1 2 null
3 3 1 null
4 2 3 1
might be better structured as this:
transid prodsold deptid
1 1 1
2 1 1
2 2 2
3 3 1
3 1 2
4 2 1
4 3 2
4 1 3
I think that would make your queries easier to write.

Resources