MDX: This query optimization - ssas

for displaying 278 records,taking 2 mins 47 seconds is there any way to optimization the query.
SELECT {[Measures].[Mins0] ,
[Measures].[Mins10] ,
[Measures].[Mins20] ,
[Measures].[MinsAbove20] ,
[Measures].[CCMPatientCnt] } ON COLUMNS ,
NONEMPTY(([DimManagedPopulation].[ManagedPopulationKey].[ManagedPopulationKey],
[DimManagedPopulation].[ManagedPopulationName].[ManagedPopulationName]),
[Measures].[CCMPatientCnt])
ON rows FROM [NavigateCube]
WHERE ([DimAnchorDate].[Date Key].&[20160331]);

It is difficult to suggest something but can you please try following code and report the outcome ?
SELECT
{
[Measures].[Mins0] ,
[Measures].[Mins10] ,
[Measures].[Mins20] ,
[Measures].[MinsAbove20] ,
[Measures].[CCMPatientCnt]
}
ON COLUMNS ,
NONEMPTY(
(
[DimManagedPopulation].[ManagedPopulationKey].[ManagedPopulationKey],
[DimManagedPopulation].[ManagedPopulationName].[ManagedPopulationName]
),
([Measures].[CCMPatientCnt], [DimAnchorDate].[Date Key].&[20160331])
)
ON rows
FROM [NavigateCube]
WHERE ([DimAnchorDate].[Date Key].&[20160331]);

Also it might help to move the set on rows into a WITH clause:
WITH
SET [PopSet] AS
NonEmpty
(
(
[DimManagedPopulation].[ManagedPopulationKey].[ManagedPopulationKey]
,[DimManagedPopulation].[ManagedPopulationName].[ManagedPopulationName]
)
,(
[Measures].[CCMPatientCnt]
,[DimAnchorDate].[Date Key].&[20160331]
)
)
SELECT
{
[Measures].[Mins0]
,[Measures].[Mins10]
,[Measures].[Mins20]
,[Measures].[MinsAbove20]
,[Measures].[CCMPatientCnt]
} ON COLUMNS
,[PopSet] ON ROWS
FROM [NavigateCube]
WHERE
[DimAnchorDate].[Date Key].&[20160331];

Related

Transpose row to column in SQL Server

I have a table like below:
Type PKG_HA_01_ON PKG_HA_03_ON PKG_HA_04_ON PKG_HA_05_ON PKG_HA_06_ON PKG_HA_09_ON
duration 18.6694 60 15.1951 56.2068 13.6808 13.8404
counter 5 0 5 11 2 0
The first row is the header. Now, I would like to transpose table into this
Machine Duration Counter
PKG_HA_01_ON 18.6694 5
PKG_HA_03_ON 60 0
...
I have tried unpivot but the result is not desired table.
Thanks in advance,
Try this:
create table unpivot_raw(
[Type] nvarchar(255)
, PKG_HA_01_ON float null
, PKG_HA_03_ON float null
, PKG_HA_04_ON float null
, PKG_HA_05_ON float null
, PKG_HA_06_ON float null
, PKG_HA_09_ON float null
)
insert into unpivot_raw
select 'duration', 18.6694, 60, 15.1951, 56.2068, 13.6808, 13.8404
union
select 'counter', 5, 0, 5, 11, 2, 0
select
*
from
(
select
[Type]
, vl
, Machine
from
(
select
[Type]
, PKG_HA_01_ON
, PKG_HA_03_ON
, PKG_HA_04_ON
, PKG_HA_05_ON
, PKG_HA_06_ON
, PKG_HA_09_ON
from unpivot_raw
) p
unpivot
(
vl for Machine in
(
PKG_HA_01_ON
, PKG_HA_03_ON
, PKG_HA_04_ON
, PKG_HA_05_ON
, PKG_HA_06_ON
, PKG_HA_09_ON
)
) unpvt
) base
pivot
(
max(vl) for [Type] in (duration, counter )
) pvt
I recommend using cross apply to unpivot and then aggregation:
select machine,
max(case when type = 'duration' then val end) as duration,
max(case when type = 'counter' then val end) as counter
from t cross apply
(values ('PKG_HA_01_ON', PKG_HA_01_ON),
('PKG_HA_03_ON', PKG_HA_03_ON),
('PKG_HA_04_ON', PKG_HA_04_ON),
('PKG_HA_05_ON', PKG_HA_05_ON),
('PKG_HA_06_ON', PKG_HA_06_ON),
('PKG_HA_09_ON', PKG_HA_09_ON)
) v(machine, val)
group by machine;
I much, much prefer this over pivot/unpivot. Why? APPLY implements a lateral join, which is a powerful construct in SQL (and part of the SQL standard albeit with slightly different syntax). Unpivoting is a nice introduction to this feature.
The pivoting functions are bespoke functions and not part of the standard. They also do not generalize in any way, being designed for a single purpose.

Get Pivot values on specific condition

I have query in SQL SEVRER -
SELECT alarm,annual_calendar,chronograph,day_flag,equation_of_time,flyback_chronograph,
gmt_time,jumping_hour,minute_repeater,moon_phase,perpetual_calendar,power_reserve,seconds_flag
,split_seconds_chrono,tachymeter,tourbillon,ultra_thin,world_time,catalog_item_id
FROM catalog_item_watches where alarm is not null
order by id desc
which return output like
And i want result like
Thanks in advance.
First make UNPIVOT, then exclude the N values. After that make a PIVOT. You may want to make it dynamic.
It should be something like this:
SELECT *
FROM
(
SELECT [catalog_item_id]
,[column]
,'Web' + CAST(DENSE_RANK() OVER(PARTITION BY [catalog_item_id] ORDER BY [column]) AS VARCHAR(12))
FROM
(
SELECT [catalog_item_id], [alarm], [annual_calendar], [chronograph], [day_flag], [equation_of_time], [flyback_chronograph], [ gmt_time], [jumping_hour], [minute_repeater], [moon_phase], [perpetual_calendar], [power_reserve], [seconds_flag], [split_seconds_chrono], [tachymeter], [tourbillon], [ultra_thin], [world_time]
FROM catalog_item_watches
where [alarm] is not null
) DS
UNPIVOT
(
[value] FOR [column] IN ([alarm], [annual_calendar], [chronograph], [day_flag], [equation_of_time], [flyback_chronograph], [ gmt_time], [jumping_hour], [minute_repeater], [moon_phase], [perpetual_calendar], [power_reserve], [seconds_flag], [split_seconds_chrono], [tachymeter], [tourbillon], [ultra_thin], [world_time])
) UNPVT
WHERE UNPVT.[value] = 'Y'
) DataSource ([catalog_item_id], [column_value], [column_name])
PIVOT
(
MAX([column_value]) FOR [column_name] IN ([web1], [web2], [web3], [web4], [web5], [web6], [web7], [web8], [web9], [web10], [web11], [web12], [web13], [web14], [web15], [web16], [web17], [web18])
) PVT

sql count new id that did not exists before for each month

I have the follow set of data
enter image description here
how can I write the sql to gives the result on right side?
that is the counting of unique id that did appeared previously for each month.
After long time of reading and reading his question, Ssiu wanted to ask the following:
So here is the test data in MS SQL: at that time he didn't clarify on postgresql
create table tmp1 (
ddate datetime
, iid int
)
insert into tmp1 values
('2017-11-01',1)
,('2017-11-02',2)
,('2017-11-03',3)
,('2017-11-04',4)
,('2017-11-05',5)
,('2017-11-06',5)
,('2017-11-07',5)
,('2017-12-01',1)
,('2017-12-02',2)
,('2017-12-03',3)
,('2017-12-04',6)
,('2017-12-05',7)
,('2018-01-01',1)
,('2018-01-02',2)
,('2018-01-03',3)
,('2018-01-04',4)
,('2018-01-05',8)
Disclaimer: The following is not the best approach for this problem. It is not applicable for more months, however it can give Ssiu a clue.
with cte(mmonth, iid) as (
select distinct convert(varchar(7), ddate, 120) mmonth
, iid
from tmp1
)
, cte_201711 as (
select * from cte where mmonth = '2017-11'
)
, cte_201712 as (
select * from cte where mmonth = '2017-12'
)
, cte_201801 as (
select * from cte where mmonth = '2018-01'
)
, cte_cnt201712 as(
select cte_201711.mmonth as mm201711
, cte_201711.iid as id201711
, cte_201712.mmonth as mm201712
, cte_201712.iid as id201712
from cte_201711
full outer join cte_201712
on cte_201712.iid = cte_201711.iid
)
, cte_cnt201801 as (
select cte_201711.mmonth as mm201711
, cte_201711.iid as id201711
, cte_201712.mmonth as mm201712
, cte_201712.iid as id201712
, cte_201801.mmonth as mm201801
, cte_201801.iid as id201801
from cte_201711
full outer join cte_201712
on cte_201712.iid = cte_201711.iid
full outer join cte_201801
on cte_201801.iid = cte_201712.iid
or cte_201801.iid = cte_201711.iid
)
--select * from cte_cnt201801 order by isnull(mm201711,'z'), isnull(mm201712,'z')
select '2017-12' mmonth, count(*) Ssiu
from cte_cnt201712
where mm201711 is null
union all
select '2018-01' mmonth, count(*) Ssiu
from cte_cnt201801
where mm201711 is null
and mm201712 is null
Note the data for the cte_cnt201801 CTE:
select * from cte_cnt201801 order by isnull(mm201711,'z'), isnull(mm201712,'z')
So the result for the above query is:

"end-of-file on communication channel" error with UNION of DISTINCT columns

I'm cleaning up SQL code from a previous engineer (not a programmer).
One query UNIONs the results to 2 almost identical queries, with an exactly identical sub-query, and the original code has a lot of "where" clauses (in both queries) to filter the data.
I am trying to use "with" tables to filter the data first, and then do the sub-queries and the union.
I keep getting a generic "end-of-file on communication channel" error during the "Prepare" step, but when I remove the DISTINCT clause from the sub-queries, it works - but it doesn't give me the results I need.
Here is the code I've "reduced" to show the error:
with
FilteredData as
(
select
ST.part
, ST.order_No
, ST.induct_Date
, ST.complete_Date
from
Some_Table ST
where
(
ST.part is not null
and ST.order_No is not null
)
-- MUCH more filtering goes on here, to limit the number of records to look at
)
,
TempTable_01A as
(
select
FD.part
, count( DISTINCT FD.part ) Count_1 -- The DISTINCT needs to be removed for it to compile
, 0 Count_2
, 0 AvgLengthOpen
from
FilteredData FD
where
FD.induct_Date is not null
and ( FD.induct_Date >= to_date( '01-01-2013', 'MM-DD-YYYY' ) )
and ( FD.induct_Date < ( to_date( '01-31-2013', 'MM-DD-YYYY' ) + 1 ) )
group by
FD.part
)
,
TempTable_01B as
(
select
FD.part
, 0 Count_1
, count( DISTINCT FD.part ) Count_2 -- The DISTINCT needs to be removed for it to compile
, avg( FD.complete_Date - FD.induct_Date ) AvgLengthOpen
from
FilteredData FD
where
FD.complete_Date is not null
and ( FD.complete_Date >= to_date( '01-01-2013', 'MM-DD-YYYY' ) )
and ( FD.complete_Date < ( to_date( '01-31-2013', 'MM-DD-YYYY' ) + 1 ) )
group by
FD.part
)
,
UnionTable as
(
select
TT_A.part
, TT_A.Count_1
, TT_A.Count_2
, TT_A.AvgLengthOpen
from
TempTable_01A TT_A
union
select
TT_B.part
, TT_B.Count_1
, TT_B.Count_2
, TT_B.AvgLengthOpen
from
TempTable_01B TT_B
)
select
UT.part
, max( UT.Count_1 ) MaxCount_1
, max( UT.Count_2 ) MaxCount_2
, max( UT.AvgLengthOpen ) MaxAvgLengthOpen
from
UnionTable UT
group by
UT.part
order by
1
NOTE: I am using Oracle SQL, version 10.0.2.1697. I get this same error whether I'm using PLSQL Developer, or my Perl program.

speed up SQL Query

I have a query which is taking some serious time to execute on anything older than the past, say, hours worth of data. This is going to create a view which will be used for datamining, so the expectations are that it would be able to search back weeks or months of data and return in a reasonable amount of time (even a couple minutes is fine... I ran for a date range of 10/3/2011 12:00pm to 10/3/2011 1:00pm and it took 44 minutes!)
The problem is with the two LEFT OUTER JOINs in the bottom. When I take those out, it can run in about 10 seconds. However, those are the bread and butter of this query.
This is all coming from one table. The ONLY thing this query returns differently than the original table is the column xweb_range. xweb_range is a calculated field column (range) which will only use the values from [LO,LC,RO,RC]_Avg where their corresponding [LO,LC,RO,RC]_Sensor_Alarm = 0 (do not include in range calculation if sensor alarm = 1)
WITH Alarm (sub_id,
LO_Avg, LO_Sensor_Alarm, LC_Avg, LC_Sensor_Alarm, RO_Avg, RO_Sensor_Alarm, RC_Avg, RC_Sensor_Alarm) AS (
SELECT sub_id, LO_Avg, LO_Sensor_Alarm, LC_Avg, LC_Sensor_Alarm, RO_Avg, RO_Sensor_Alarm, RC_Avg, RC_Sensor_Alarm
FROM dbo.some_table
where sub_id <> '0'
)
, AddRowNumbers AS (
SELECT rowNumber = ROW_NUMBER() OVER (ORDER BY LO_Avg)
, sub_id
, LO_Avg, LO_Sensor_Alarm
, LC_Avg, LC_Sensor_Alarm
, RO_Avg, RO_Sensor_Alarm
, RC_Avg, RC_Sensor_Alarm
FROM Alarm
)
, UnPivotColumns AS (
SELECT rowNumber, value = LO_Avg FROM AddRowNumbers WHERE LO_Sensor_Alarm = 0
UNION ALL SELECT rowNumber, LC_Avg FROM AddRowNumbers WHERE LC_Sensor_Alarm = 0
UNION ALL SELECT rowNumber, RO_Avg FROM AddRowNumbers WHERE RO_Sensor_Alarm = 0
UNION ALL SELECT rowNumber, RC_Avg FROM AddRowNumbers WHERE RC_Sensor_Alarm = 0
)
SELECT rowNumber.sub_id
, cds.equipment_id
, cds.read_time
, cds.LC_Avg
, cds.LC_Dev
, cds.LC_Ref_Gap
, cds.LC_Sensor_Alarm
, cds.LO_Avg
, cds.LO_Dev
, cds.LO_Ref_Gap
, cds.LO_Sensor_Alarm
, cds.RC_Avg
, cds.RC_Dev
, cds.RC_Ref_Gap
, cds.RC_Sensor_Alarm
, cds.RO_Avg
, cds.RO_Dev
, cds.RO_Ref_Gap
, cds.RO_Sensor_Alarm
, COALESCE(range1.range, range2.range) AS xweb_range
FROM AddRowNumbers rowNumber
LEFT OUTER JOIN (SELECT rowNumber, range = MAX(value) - MIN(value) FROM UnPivotColumns GROUP BY rowNumber HAVING COUNT(*) > 1) range1 ON range1.rowNumber = rowNumber.rowNumber
LEFT OUTER JOIN (SELECT rowNumber, range = AVG(value) FROM UnPivotColumns GROUP BY rowNumber HAVING COUNT(*) = 1) range2 ON range2.rowNumber = rowNumber.rowNumber
INNER JOIN dbo.some_table cds
ON rowNumber.sub_id = cds.sub_id
It's difficult to understand exactly what your query is trying to do without knowing the domain. However, it seems to me like your query is simply trying to find, for each row in dbo.some_table where sub_id is not 0, the range of the following columns in the record (or, if only one matches, that single value):
LO_AVG when LO_SENSOR_ALARM=0
LC_AVG when LC_SENSOR_ALARM=0
RO_AVG when RO_SENSOR_ALARM=0
RC_AVG when RC_SENSOR_ALARM=0
You constructed this query assigning each row a sequential row number, unpivoted the _AVG columns along with their row number, computed the range aggregate grouping by row number and then joining back to the original records by row number. CTEs don't materialize results (nor are they indexed, as discussed in the comments). So each reference to AddRowNumbers is expensive, because ROW_NUMBER() OVER (ORDER BY LO_Avg) is a sort.
Instead of cutting this table up just to join it back together by row number, why not do something like:
SELECT cds.sub_id
, cds.equipment_id
, cds.read_time
, cds.LC_Avg
, cds.LC_Dev
, cds.LC_Ref_Gap
, cds.LC_Sensor_Alarm
, cds.LO_Avg
, cds.LO_Dev
, cds.LO_Ref_Gap
, cds.LO_Sensor_Alarm
, cds.RC_Avg
, cds.RC_Dev
, cds.RC_Ref_Gap
, cds.RC_Sensor_Alarm
, cds.RO_Avg
, cds.RO_Dev
, cds.RO_Ref_Gap
, cds.RO_Sensor_Alarm
--if the COUNT is 0, xweb_range will be null (since MAX will be null), if it's 1, then use MAX, else use MAX - MIN (as per your example)
, (CASE WHEN stats.[Count] < 2 THEN stats.[MAX] ELSE stats.[MAX] - stats.[MIN] END) xweb_range
FROM dbo.some_table cds
--cross join on the following table derived from values in cds - it will always contain 1 record per row of cds
CROSS APPLY
(
SELECT COUNT(*), MIN(Value), MAX(Value)
FROM
(
--construct a table using the column values from cds we wish to aggregate
VALUES (LO_AVG, LO_SENSOR_ALARM),
(LC_AVG, LC_SENSOR_ALARM),
(RO_AVG, RO_SENSORALARM),
(RC_AVG, RC_SENSOR_ALARM)
) x (Value, Sensor_Alarm) --give a name to the columns for _AVG and _ALARM
WHERE Sensor_Alarm = 0 --filter our constructed table where _ALARM=0
) stats([Count], [Min], [Max]) --give our derived table and its columns some names
WHERE cds.sub_id <> '0' --this is a filter carried over from the first CTE in your example