My table structure is below :
MyTable (ID Int, AccID1 Int, AccID2 Int, AccID3 int)
ID AccID1 AccID2 AccID3
---- -------- -------- --------
1 12 2 NULL
2 4 12 1
3 NULL NULL 5
4 7 NULL 1
I want to create indexed view with below output :
ID Level Value
---- ----- -------
1 1 12
1 2 2
2 1 4
2 2 12
2 3 1
3 3 5
4 1 7
4 3 1
EDIT :
My table is very huge and I want to have above output.
I can Get my query such as below :
Select ID,
Case StrLevel
When 'AccID1' Then 1
When 'AccID2' Then 2
Else 3
End AS [Level],
AccID as Value
From (
Select A.ID, A.AccID1, A.AccID2, A.AccID3
From MyTable A
)as p
UNPIVOT (AccID FOR [StrLevel] IN (AccID1, AccID2, AccID3)) AS unpvt
or
Select *
from (
select MyTable.ID,
num.n as [Level],
Case Num.n
When 1 Then MyTable.AccID1
When 2 Then MyTable.AccID2
Else MyTable.AccID3
End AS AccID
from myTable
cross join (select 1
union select 2
union select 3)Num(n)
)Z
Where Z.AccID IS NOT NULL
or
Select A.ID,
2 AS [Level],
A.AccID1 AS AccID
From MyTable A
Where A.AccID1 IS NOT NULL
Union
Select A.ID,
2 AS [Level],
A.AccID2
From MyTable A
Where A.AccID2 IS NOT NULL
Union
Select A.ID,
3 AS [Level],
A.AccID3
From MyTable A
Where A.AccID3 IS NOT NULL
But Above query is slow and I want to have indexed view to have better performance.
and in indexed view I can't use UNION or UNPIVOT or CROSS JOIN in indexed view.
What if you created a Numbers table to essentially do the work of your illegal CROSS JOIN?
Create Table Numbers (number INT NOT NULL PRIMARY KEY)
Go
Insert Numbers
Select top 30000 row_number() over (order by (select 1)) as rn
from sys.all_objects s1 cross join sys.all_objects s2
go
Create view v_unpivot with schemabinding
as
Select MyTable.ID,
n.number as [Level],
Case n.number
When 1 Then MyTable.AccID1
When 2 Then MyTable.AccID2
Else MyTable.AccID3
End AS AccID
From dbo.Mytable
Join dbo.Numbers n on n.number BETWEEN 1 AND 3
go
Create unique clustered index pk_v_unpivot on v_unpivot (ID, [Level])
go
Select
ID,
[Level],
AccID
From v_unpivot with (noexpand)
Where AccID IS NOT NULL
Order by ID, [Level]
The WHERE AccID IS NOT NULL must be part of the query because derived tables are not allowed in indexed views.
Related
I have a RELATION table
NUM1 | NUM2 | NUM3
-- --- -----
1 2 3
2 4 5
3 4 null
3 4 null
and the actual INFO table where NUM is primary key.
NUM | A_LOT_OF_OTHER_INFO
--- --------------------
1 asdff
2 werwr
3 erert
4 ghfgh
5 cvbcb
I want to create a view to see the count of the NUM that appeared in any of the NUM1, NUM2, NUM3 of the RELATION table.
MY_VIEW
NUM | A_LOT_OF_OTHER_INFO | TOTAL_COUNT
--- -------------------- ------------
1 asdff 1
2 werwr 2
3 erert 3
4 ghfgh 3
5 cvbcb 1
I can do this by doing three selects from RELATION table and UNION them, but I do not want to use UNION because the tables have a lot of records, MY_VIEW is already large enough and I am looking for a better way to join to the RELATION table in the view. Can you suggest a way?
What i would try is to unpivot the relation table.
After that join the info table on the values and count the number of times the val gets repeated.
create table relation(num1 int,num2 int, num3 int);
insert into relation values(1,2,3);
insert into relation values(2,4,5);
insert into relation values(3,4,null);
create table info(num int, a_lot_of_other_info varchar2(100));
insert into info
select 1,'asdff' from dual union all
select 2,'werwr' from dual union all
select 3,'erert' from dual union all
select 4,'ghfgh' from dual union all
select 5,'cvbcb' from dual
select a.num
,max(a_lot_of_other_info) as a_lot_of_other_info
,count(*) as num_of_times
from info a
join (select val
from relation a
unpivot(val for x in (num1,num2,num3))
)b
on a.num=b.val
group by a.num
order by 1
I would suggest a correlated subquery:
select i.*,
(select ((case when r.num1 = i.num then 1 else 0 end) +
(case when r.num2 = i.num then 1 else 0 end) +
(case when r.num3 = i.num then 1 else 0 end)
)
from relation r
where i.num in (r.num1, r.num2, r.num3)
) as total_count
from info i;
If performance is a consideration, it might be faster to use left joins:
select i.*,
((case when r1.num1 is not null then 1 else 0 end) +
(case when r2.num1 is not null then 1 else 0 end) +
(case when r3.num1 is not null then 1 else 0 end)
) as total_count
from info i left join
relation r1
on i.num = r1.num1 left join
relation r2
on i.num = r2.num2 left join
relation r3
on i.num = r3.num3;
In particular, this will make optimal use of three separate indexes on relation: relation(num1), relation(num2), and relation(num3).
It seems what you want is UNPIVOT. Perhaps easiest to do with a cross join in this case:
select NUM, count(*) as TOTAL_COUNT
from (
select decode(column_value, 1, NUM1, 2, NUM2, 3, NUM3) as NUM
from RELATION cross join table(sys.odcinumberlist(1,2,3))
)
group by NUM
;
Then join this to the second table; the join part is really irrelevant here.
suppose i have a data like that
ID ParentID Name
1 null a
2 1 b
3 2 c
4 1 d
5 4 e
if i use cte(common table expression) provided by sql it shows me result like this
ID ParentID Name
1 null a
2 1 b
4 1 d
3 2 c
5 4 e
but i want to arrange data like, query should complete first node till end , then move to other node . like
ID ParentID Name
1 null a
2 1 b
3 2 c
4 1 d
5 4 e
Note: i have a primary key with datatype :uniqueidentifier so i cannot use order by clause after CTE
Example
Declare #Top int = null --<< Sets top of Hier Try 2
;with cteP as (
Select ID
,ParentID
,Name
,Path = cast('/'+[ID]+'/' as varchar(500))
From YourTable
Where IsNull(#Top,-1) = case when #Top is null then isnull(ParentID ,-1) else ID end
Union All
Select r.ID
,r.ParentID
,r.Name
,cast(p.path + '/'+r.[ID]+'/' as varchar(500))
From YourTable r
Join cteP p on r.ParentID = p.ID)
Select ID
,ParentID
,Name
From cteP A
Order By Path
Returns
Without seeing your query, I think you can do something like this:
WITH CTE_Example
AS
(
YOUR QUERY
)
SELECT *
FROM CTE_Example
ORDER BY ID
I have a scenario to get the respective field value of "Max" and "Min" records
Please find the sample data below
-----------------------------------------------------------------------
ID Label ProcessedDate
-----------------------------------------------------------------------
1 Label1 11/01/2016
2 Label2 11/02/2016
3 Label3 11/03/2016
4 Label4 11/04/2016
5 Label5 11/05/2016
I have the "ID" field populated in another table as a foreign key. While querying those records in that table based on the "ID" field I need to get the "Label" field of "Max" Processed date and "Min" processed date.
-----------------------------------------------------------------------
ID LabelID GroupingField
-----------------------------------------------------------------------
1 1 101
2 2 101
3 3 101
4 4 101
5 5 101
6 1 102
7 2 102
8 3 102
9 4 102
And the final result set I expect it to look something like this.
-----------------------------------------------------------------------
GroupingField FirstProcessed LastProcessed
-----------------------------------------------------------------------
101 Label1 Label5
102 Label1 Label4
I have 'almost' managed to get this above result using rank function but still not satisfied with it. So I am looking if someone can provide me with a better option.
Thanks,
Prakazz
CREATE TABLE #Details (ID INT,LabelID INT,GroupingField INT)
CREATE TABLE #Details1 (ID INT,Label VARCHAR(100),ProcessedDate VARCHAR(100))
INSERT INTO #Details1 (ID ,Label ,ProcessedDate )
SELECT 1,'Label1','11/01/2016' UNION ALL
SELECT 2,'Label2','11/02/2016' UNION ALL
SELECT 3,'Label3','11/03/2016' UNION ALL
SELECT 4,'Label4','11/04/2016' UNION ALL
SELECT 5,'Label5','11/05/2016'
INSERT INTO #Details (ID ,LabelID ,GroupingField )
SELECT 1,1,101 UNION ALL
SELECT 2,2,101 UNION ALL
SELECT 3,3,101 UNION ALL
SELECT 4,4,101 UNION ALL
SELECT 5,5,101 UNION ALL
SELECT 6,1,102 UNION ALL
SELECT 7,2,102 UNION ALL
SELECT 8,3,102 UNION ALL
SELECT 9,4,102
;WITH CTE (GroupingField , MAXId ,MinId) AS
(
SELECT GroupingField,MAX(LabelID) MAXId,MIN(LabelID) MinId
FROM #Details
GROUP BY GroupingField
)
SELECT GroupingField ,B.Label FirstProcessed, A.Label LastProcessed
FROM CTE
JOIN #Details1 A ON MAXId = A.ID
JOIN #Details1 B ON MinId = B.ID
You can use SQL Row_Number() function using Partition By as follows with a combination of Group By
;with cte as (
select
t.Label, t.ProcessedDate,
g.GroupingField,
ROW_NUMBER() over (partition by GroupingField Order By ProcessedDate ASC) minD,
ROW_NUMBER() over (partition by GroupingField Order By ProcessedDate DESC) maxD
from tbl t
inner join GroupingFieldTbl g
on t.ID = g.LabelID
)
select GroupingField, max(FirstProcessed) FirstProcessed, max(LastProcessed) LastProcessed
from (
select
GroupingField,
FirstProcessed = CASE when minD = 1 then Label else null end,
LastProcessed = CASE when maxD = 1 then Label else null end
from cte
where
minD = 1 or maxD = 1
) t
group by GroupingField
order by GroupingField
I also used CTE expression to make coding easier and understandable
Output is as
I have three tables:
1. Flat Discount
2. Promotion
3. weeklyorder
When i join these table and take union i got 2 row with same data but one different .. how to merge it to show only one row.
Query:
SELECT skuMaster.SKU,
(skuMaster.MinimumStock - COUNT(*)) as ReorderQuantity,
'LowInventory' as descp
FROM SKUMaster skuMaster
JOIN InventoryMaster inventoryMaster ON skuMaster.SKU = inventoryMaster.SKU
GROUP BY skuMaster.sku, skuMaster.MinimumStock, skuMaster.Name
HAVING COUNT(*) < skuMaster.MinimumStock
UNION
SELECT WeeklyOrderList.SKU,
WeeklyOrderList.Quantity as ReorderQuantity,
'NoPO' as descp
FROM WeeklyOrderList
WHERE WeeklyOrderList.POCGen = 'true'
result :
SKU ReorderQuantity descp
1 1 LowInventory
2 2 LowInventory
2 2 NoPO
6 5 LowInventory
here 2nd And 3rd are alomost same only description is different.
can we combine them and show only one row with descp as lowinventory and NOPO
SKU ReorderQuantity descp
1 1 LowInventory
2 2 LowInventory NoPo
6 5 LowInventory
same as above suppose we have table below
SKU ReorderQuantity
1 1
2 5
2 10
6 5
here output should be Max reorder quantity of same sku
Result:
SKU ReorderQuantity
1 1
2 10
6 5
;WITH CTE AS
(
SELECT skuMaster.SKU,
(skuMaster.MinimumStock - COUNT(*)) as ReorderQuantity,
'LowInventory' as descp
FROM SKUMaster skuMaster
JOIN InventoryMaster inventoryMaster ON skuMaster.SKU = inventoryMaster.SKU
GROUP BY skuMaster.sku, skuMaster.MinimumStock, skuMaster.Name
HAVING COUNT(*) < skuMaster.MinimumStock
UNION
SELECT WeeklyOrderList.SKU,
WeeklyOrderList.Quantity as ReorderQuantity,
'NoPO' as descp
FROM WeeklyOrderList
WHERE WeeklyOrderList.POCGen = 'true'
)
SELECT DISTINCT
a.SKU,
a.ReorderQuantity,
descp = STUFF((SELECT ', ' + b.descp
FROM CTE b
WHERE b.ReorderQuantity = a.ReorderQuantity
FOR XML PATH('')), 1, 2, '')
FROM CTE a
just an example for above output mentioned
DECLARE #t TABLE
(
SKU INT,
ReorderQuantity INT
)
INSERT INTO #t (SKU,ReorderQuantity)
VALUES (1,1), (2,5), (2,10), (6,5)
SELECT t.SKU,tt.Qty
FROM #t t
INNER JOIN (SELECT MAX(ReorderQuantity)as Qty, SKU
FROM #t
GROUP BY SKU) tt
ON tt.SKU = t.SKU
GROUP BY t.SKU,tt.Qty
I am using SQL Server 2008 R2.
I have the following data:
ID Value OrderNumber
1 A NULL
2 E 4
3 C NULL
4 B NULL
5 F 2
6 D NULL
i want to write a query that must fetch data ordering by OrderNumber column considering OrderNumber values. The query result must be below:
ID Value OrderNumber
1 A NULL
5 F 2 --indicates row must be second in result set.
3 C NULL
2 E 4 --indicates row must be fourth in result set.
4 B NULL
6 D NULL
Thanks for reading and your answers.
I've tried a number of different ways, but the only way I can find that produces the required results in a guaranteed way is:
declare #t table (ID int not null,Value char(1) not null,OrderNumber int null)
insert into #T(ID,Value,OrderNumber) values
(1,'A',NULL),
(2,'E',4),
(3,'C',NULL),
(4,'B',NULL),
(5,'F',2),
(6,'D',NULL)
;With Nbrs as (
select ROW_NUMBER() OVER (ORDER BY ID) as n from #t
), AvailableNbrs as (
select n,ROW_NUMBER() OVER (ORDER BY n) as rn from Nbrs where n not in (select OrderNumber from #t where OrderNumber is not null)
), RequiredOrders as (
select ID,ROW_NUMBER() OVER (ORDER BY ID) as rn from #t where OrderNumber is null
)
select
*,COALESCE(OrderNumber,an.n) as FinalOrder
from
#t t
left join
RequiredOrders ro
on
t.ID = ro.ID
left join
AvailableNbrs an
on
ro.rn = an.rn
order by COALESCE(OrderNumber,an.n)
Where we use a few CTEs to find OrderNumbers that aren't currently assigned, and to match those 1-1 with rows which have no OrderNumber.
Results:
|--------- #t --------------| |----- RequiredOrders ---------| |----- AvailableNbrs -------------------| |- COALESCE -------|
ID Value OrderNumber ID rn n rn FinalOrder
----------- ----- ----------- ----------- -------------------- -------------------- -------------------- --------------------
1 A NULL 1 1 1 1 1
5 F 2 NULL NULL NULL NULL 2
3 C NULL 3 2 3 2 3
2 E 4 NULL NULL NULL NULL 4
4 B NULL 4 3 5 3 5
6 D NULL 6 4 6 4 6
Found a much better solution than the accepted answer:
declare #t table(id int, value char, ordernumber int)
insert #t values(1,'A', null)
insert #t values(2,'E',4)
insert #t values(3,'C',NULL)
insert #t values(4,'B',NULL)
insert #t values(5,'F',2)
insert #t values(6,'D',NULL)
;with a as
(
select *, row_number() over (order by id)+.1 rn1 from #t
where ordernumber is null
union all
select *, ordernumber - rank() over (order by ordernumber)+1 rn1 from #t
where ordernumber is not null
)
select * from a order by rn1, ordernumber
Try this:
SELECT *
FROM tableName
Order BY CASE WHEN OrderNumber IS NULL THEN ID ELSE OrderNumber END