MDX: Joining months with total - sql-server

I want to create table like this:
[January] [February] ...other months... [Total for Year]
item1
item2
item3
It's easy to create 2 different queries, for months and total, like this:
SELECT
[Time].[Month].[Month] ON COLUMNS,
TOPCOUNT([Items], 5, [Count]) ON ROWS
FROM [Cube]
WHERE([Time].[Year].[Year].&[2015-01-01T00:00:00])
and
WITH
MEMBER [Total] AS SUM([Count], [Time].[Year].[Year].&[2015-01-01T00:00:00])
SELECT
[Total] ON COLUMNS,
TOPCOUNT([Items], 5, [Count]) ON ROWS
FROM [Cube]
but how to concatenate them or write single one?

You could expand the WITH statement like this:
WITH
MEMBER [Time].[Month].[All].[Total] AS --<<THIS IS HOSTED IN SAME HIERARCHY AS THE SET THAT FOLLOWS
Sum
(
[Count]
,[Time].[Year].[Year].&[2015-01-01T00:00:00]
)
SET [mths] AS
Exists
(
[Time].[Month].[Month].MEMBERS
,[Time].[Year].[Year].&[2015-01-01T00:00:00]
)
SET [concatenatet_set] AS
{
--<<THE FOLLOWING CAN BE BROUGHT TOGETHER AS THEY HAVE THE SAME "DIMENSIONALITY" I.E. FROM THE SAME HIERARCHY
[mths]
,[Time].[Month].[All].[Total]
}
SELECT
[concatenatet_set] ON COLUMNS
,TopCount
(
[Items]
,5
,[Count]
) ON ROWS
FROM [Cube];
Here is the script I have used to test the above idea against AdvWrks:
WITH
MEMBER [Date].[Calendar].[All].[Total] AS
Sum
(
[Measures].[Internet Sales Amount]
,(
[Date].[Calendar].[All Periods]
,[Date].[Calendar Year].&[2007]
,[Date].[Calendar Quarter of Year].&[CY Q1]
)
)
SET [mths] AS
Exists
(
[Date].[Calendar].[Month]
,(
[Date].[Calendar Year].&[2007]
,[Date].[Calendar Quarter of Year].&[CY Q1]
)
)
SET [concatenatet_set] AS
{
[mths]
,[Date].[Calendar].[All].[Total]
}
SELECT
[concatenatet_set] ON COLUMNS
,TopCount
(
NonEmpty
(
[Product].[Subcategory].[Subcategory]
,(
[Date].[Calendar Year].&[2007]
,[Date].[Calendar Quarter of Year].&[CY Q1]
)
)
,5
,[Measures].[Internet Sales Amount]
) ON ROWS
FROM [Adventure Works]
WHERE
[Measures].[Internet Sales Amount];
It results in the following which seems reasonable:

Try just changing your first query to:
SELECT
[Time].[Month].Members ON COLUMNS,
TOPCOUNT([Items], 5, [Count]) ON ROWS
FROM [Cube]
WHERE([Time].[Year].[Year].&[2015-01-01T00:00:00])

Related

How to select the top 1 in case distinct returns 2 rows

I have a select distinct query that can return 2 rows with the same code since not all columns have the same value. Now my boss wants to get the first one. So how to I do it. Below is the sample result. I want only to return the get the first two unique pro
Use row_number in your query. Please find this link for more info link
; with cte as (
select row_number() over (partition by pro order by actual_quantity) as Slno, * from yourtable
) select * from cte where slno = 1
Your chances to get the proper answer can be much higher if you spend some time to prepare the question properly. Provide the DDL and sample data, as well as add the desired result.
To solve your problem, you need to know the right uniqueness order to get 1 record per window group. Google for window functions. In my example the uniqueness is --> Single row for every pro with earliest proforma_invoice_received_date date and small amount per this date.
DROP TABLE IF EXISTS #tmp;
GO
CREATE TABLE #tmp
(
pro VARCHAR(20) ,
actual_quantity DECIMAL(12, 2) ,
proforma_invoice_received_date DATE ,
import_permit DATE
);
GO
INSERT INTO #tmp
( pro, actual_quantity, proforma_invoice_received_date, import_permit )
VALUES ( 'N19-00945', 50000, '20190516', '20190517' ),
( 'N19-00945', 50001, '20190516', '20190517' )
, ( 'N19-00946', 50002, '20190516', '20190517' )
, ( 'N19-00946', 50003, '20190516', '20190517' );
SELECT a.pro ,
a.actual_quantity ,
a.proforma_invoice_received_date ,
a.import_permit
FROM ( SELECT pro ,
actual_quantity ,
proforma_invoice_received_date ,
import_permit ,
ROW_NUMBER() OVER ( PARTITION BY pro ORDER BY proforma_invoice_received_date, actual_quantity ) AS rn
FROM #tmp
) a
WHERE rn = 1;
-- you can also use WITH TIES for that to save some lines of code
SELECT TOP ( 1 ) WITH TIES
pro ,
actual_quantity ,
proforma_invoice_received_date ,
import_permit
FROM #tmp
ORDER BY ROW_NUMBER() OVER ( PARTITION BY pro ORDER BY proforma_invoice_received_date, actual_quantity );
DROP TABLE #tmp;
Try this-
SELECT * FROM
(
SELECT *,
ROW_NUMBER() OVER (PARTITION BY pro ORDER BY Pro) RN
-- You need to add other columns in the ORDER BY clause
-- with 'pro' to get your desired row. other case you
-- will get first row returned by the query with only
-- order by 'pro' and this can vary for different execution
FROM your_table
)A
WHERE RN = 1
CREATE TABLE T (
A [numeric](10, 2) NULL,
B [numeric](10, 2) NULL
)
INSERT INTO T VALUES (100,20)
INSERT INTO T VALUES (100,30)
INSERT INTO T VALUES (200,40)
INSERT INTO T VALUES (200,50)
select *
from T
/*
A B
100.00 20.00
100.00 30.00
200.00 40.00
200.00 50.00
*/
select U.A, U.B
from
(select row_number() over(Partition By A Order By B) as row_num, *
from T ) U
where row_num = 1
/*
A B
100.00 20.00
200.00 40.00
*/

Detect samples with dates differences within same data column

Table:
How can I scan each individual SampleRef and flag the one that have any of the delivery dates more than 6 months apart. So from the sample above only SampleRef A has dates that are 6 months apart example 01/04/2013 and 16/02/2014 using T-SQL.
Result:
Thank you!
Couple other options for you:
MIN and MAX per SampleRef and difference of those greater than 6 months.
Or use LAG() and get the previous delivery date for each record and then see which one had a previous delivery greater than six months.
DECLARE #TestData TABLE
(
[SampleRef] CHAR(1)
, [DeliveryDate] DATE
);
INSERT INTO #TestData (
[SampleRef]
, [DeliveryDate]
)
VALUES ( 'A', '4/1/2013' )
, ( 'A', '2/3/2013' )
, ( 'A', '2/16/2014' )
, ( 'A', '6/12/2015' )
, ( 'A', '6/26/2015' )
, ( 'A', '6/26/2015' )
, ( 'A', '2/10/2015' )
, ( 'B', '6/26/2015' )
, ( 'B', '6/27/2015' )
, ( 'B', '6/28/2015' )
, ( 'B', '6/29/2015' )
, ( 'B', '6/30/2015' )
, ( 'B', '7/1/2015' );
--This looks at all dates per sampleref, min and max and filters those greater than 6 months
SELECT *
FROM (
SELECT [SampleRef]
, MIN([DeliveryDate]) AS [MinDeliveryDate]
, MAX([DeliveryDate]) AS [MaxDeliveryDate]
FROM #TestData
GROUP BY [SampleRef]
) AS [SampleRef]
WHERE DATEDIFF(
MONTH
, [SampleRef].[MinDeliveryDate]
, [SampleRef].[MaxDeliveryDate]
) > 6;
--This will get the prior delivery date for each record and then you can see all where there was a span greater than six months.
SELECT *
, DATEDIFF(
MONTH
, [SampleRef].[PreviousDelivery]
, [SampleRef].[DeliveryDate]
) AS [MonthSincePreviousDelivery]
FROM (
SELECT *
, LAG([DeliveryDate], 1, [DeliveryDate]) OVER ( PARTITION BY [SampleRef]
ORDER BY [DeliveryDate]
) AS [PreviousDelivery]
FROM #TestData
) AS [SampleRef]
WHERE DATEDIFF(
MONTH
, [SampleRef].[PreviousDelivery]
, [SampleRef].[DeliveryDate]
) > 6;
--Is there a record belonging to a SampleRef, where for any row, there is an absence of any
--delivery within six months prior, however there is some prior delivery
SELECT
DISTINCT T1.SampleRef FROM YourTable T1
WHERE EXISTS(
SELECT 0 FROM YourTable T2
WHERE
T1.SampleRef = T2.SampleRef And
Not EXISTS( -- was there no delivery in last 6 months
SELECT 0 FROM YourTable T3
WHERE T3.SampleRef = T2.SampleRef
AND
T3.DeliverYdate >= DATEADD(mm,-6,T2.DeliveryDate)
AND
T3.DeliveryDate < T2.DeliveryDate
)
And Exists --check that there was howevwer a prior delivery
(
SELECT 0 FROM YourTable T4
WHERE T4.SampleRef = T2.SampleRef
AND
T4.DeliverYdate < T2.DeliveryDate
)
)
You can use ROW_NUMBER() to order the samples within a SampleRef, then join that ordered set to itself and find any records where the next available sample is more than 6 months later. (Note that the example code below won't tell you if it's been more than 6 months since the final sample in the set - you could modify the query to do so if necessary)
You didn't specify a name for the table, so replace YourTableNameHere in the query below with the name of your table.
WITH SamplesNumberedByGroup AS (
SELECT
SampleRef,
DeliveryDate,
ROW_NUMBER() OVER (PARTITION BY SampleRef ORDER BY DeliveryDate) AS 'SampleNum'
FROM
YourTableNameHere
)
SELECT
DISTINCT
S.SampleRef
FROM
SamplesNumberedByGroup S
INNER JOIN SamplesNumberedByGroup S2 ON S.SampleRef = S2.SampleRef AND S2.SampleNum = S.SampleNum + 1
WHERE
S2.DeliveryDate > DATEADD(MONTH,6,S.DeliveryDate);
If you want to see each sample where the next available sample is more than 6 months away (instead of just seeing which sampleref has a gap of at least 6 months), use the code below instead.
WITH SamplesNumberedByGroup AS (
SELECT
SampleRef,
DeliveryDate,
ROW_NUMBER() OVER (PARTITION BY SampleRef ORDER BY DeliveryDate) AS 'SampleNum'
FROM
YourTableNameHere
)
SELECT
S.SampleRef
,S.Price
,S.DeliveryDate
FROM
SamplesNumberedByGroup S
INNER JOIN SamplesNumberedByGroup S2 ON S.SampleRef = S2.SampleRef AND S2.SampleNum = S.SampleNum + 1
WHERE
S2.DeliveryDate > DATEADD(MONTH,6,S.DeliveryDate);
If you need to include any entries that are more than 6 months old but do not have a "next" entry as well, then replace INNER JOIN with LEFT OUTER JOIN and add OR (S2.DeliveryDate IS NULL AND GETDATE() > DATEADD(MONTH,6,S.DeliveryDate) to the where statement.
Use EXISTS() to check if there is any row where the next higher row for the same SampleRef is more than 6 months DATEDIFF.

how to use Group by with top count in MDX query

I have an example where we prepared query in sql for fetching appropriate results
SQL Query-
select partnerid,BrandDesc,ActualRetailValue
from
(
select DENSE_RANK() over (partition by partnerid order by sum(ActualRetailValue) desc) as rnk,
partnerid,BrandDesc,sum(ActualRetailValue) as ActualRetailValue
from JDASales
where partnerid in (693,77)
group by partnerid,BrandDesc
) as A
where rnk <=5
order by partnerid,rnk
Output -
I want this result with mdx query.Even tryout with this code
SELECT
NON EMPTY
{[Measures].[Actual Retail Value]} ON COLUMNS
,NON EMPTY
[DimBrands].[Brand].[Brand].ALLMEMBERS
*
TopCount
(
[DimPartners].[Partner].[Partner].ALLMEMBERS
*
[DimSKU].[XXX Desc].[XXX Desc].ALLMEMBERS
,5
,[Measures].[Actual Retail Value]
) ON ROWS
FROM
(
SELECT
{[DimPartners].[Partner].&[1275]} ON COLUMNS
FROM
(
SELECT
{[Dim Date].[Fiscal Year].&[2014-01-01T00:00:00]} ON COLUMNS
FROM [SALES]
)
)
WHERE
[Dim Date].[Fiscal Year].&[2014-01-01T00:00:00];
You can amend the rows snippet to use the GENERATE function:
SELECT
NON EMPTY
{[Measures].[Actual Retail Value]} ON 0
,NON EMPTY
GENERATE(
[DimBrands].[Brand].[Brand].ALLMEMBERS AS B
,
TopCount(
B.CURRENTMEMBER
*[DimPartners].[Partner].[Partner].ALLMEMBERS
*[DimSKU].[XXX Desc].[XXX Desc].ALLMEMBERS
,5
,[Measures].[Actual Retail Value]
)
) ON ROWS
...
...
This functions usage is detailed here: https://msdn.microsoft.com/en-us/library/ms145526.aspx

need to update first non null field_x in non-normalised table

I have the following table that I have to work with.
SQL Fiddle
Basically, it is a product that stores up to 10 barcodes for a product code (simplified example). At any time, any number of those 10 barcode fields might have a value.
I have another table that has a list of product code and barcode, and need to add these to the product barcode table.
I need to perform an update so that any of the barcodes in barcodes_to_import are appended to the product_barcode table, into the first non null barcode column.
table product_barcodes
product_Code barcode_1 barcode_2 barcode_3 barcode_4 barcode_5
ABC 1 2 3
BCD 4
table barcodes_to_import
product_code barcode
ABC 7
BCD 8
Expected output:
product_Code barcode_1 barcode_2 barcode_3 barcode_4 barcode_5
ABC 1 2 3 7
BCD 4 8
create table product_barcodes(product_Code varchar(10),barcode_1 int,barcode_2 int,barcode_3 int
,barcode_4 int,barcode_5 int,barcode_6 int,barcode_7 int,barcode_8 int,barcode_9 int,barcode_10 int)
create table barcodes_to_import(product_code varchar(10),barcode int)
--Inserted Sample values as below
SELECT * FROM product_barcodes
SELECT * FROM barcodes_to_import
--Output Query
;with cte
as
(
select product_code,data,col_name
from product_barcodes
unpivot
(
data for col_name in (
barcode_1,barcode_2,barcode_3,barcode_4,barcode_5
,barcode_6,barcode_7,barcode_8,barcode_9,barcode_10
)
) upvt
)
,cte1
as
(
select *,ROW_NUMBER() OVER(PARTITION BY product_code ORDER BY col_name) as rn
from
(
select product_code, data,col_name from cte
union all
select product_code,barcode,'barcode_z' as col_name from barcodes_to_import
) t
)
select
product_Code
,SUM(1) as barcode_1
,SUM([2]) as barcode_2
,SUM([3]) as barcode_3
,SUM([4]) as barcode_4
,SUM([5]) as barcode_5
,SUM([6]) as barcode_6
,SUM([7]) as barcode_7
,SUM([8]) as barcode_8
,SUM([9]) as barcode_9
,SUM([10]) as barcode_10
from cte1
PIVOT
(
AVG(data) for rn in (1,[2],[3],[4],[5],[6],[7],[8],[9],[10])
) pvt
GROUP BY product_Code

How can I get ROLLUP Sum in MDX Query?

I use SSAS and Adventure Works DW 2008.
What is the MDX to get this?:
Measure: Reseller Sales Amount
Day : 2014/03/05
and
Month = 2014/03 ( Sum(Day 01-05) )
and
Year 2014 (Sum(Mount 01 and 02) + Sum(Day 01-05))
With
set Serial_Month as
[Date].[Calendar].Currentmember.parent.FIRSTSIBLING
:
[Date].[Calendar].Currentmember.parent
set Serial_Day as
[Date].[Calendar].Currentmember.FIRSTSIBLING
:
[Date].[Calendar].Currentmember
Select
non empty
{
[Date].[Calendar].[Date],
Serial_Day,
Serial_Month
} on columns ,
non empty {[Measures].[Reseller Sales Amount]} on rows
From [Adventure Works]
The following specifies some specific dates and then creates a calculated member.
I'm not 100% sure what you require but is the following heading in the right direction?
note: I don't have the same date ranges in my Adventure works as you.
WITH
SET [SpecificDate] AS
[Date].[Calendar].[Date].&[20080401]
SET [SpecificMonths] AS
{ [Date].[Calendar].[Month].&[2008]&[3]:
[Date].[Calendar].[Month].&[2008]&[7] }
MEMBER [Date].[Calendar].[AggregatedMonths] AS
(
AGGREGATE([SpecificMonths])
)
SET [SpecificYear] AS
[Date].[Calendar].[Calendar Year].&[2008]
MEMBER [Date].[Calendar].[CalcMember] AS
(
[Date].[Calendar].[Date].&[20080401] +
[Date].[Calendar].[Month].&[2008]&[3] +
[Date].[Calendar].[Calendar Year].&[2008]
)
Select
{
[Measures].[Reseller Sales Amount]
} ON COLUMNS,
{
[SpecificDate],
[SpecificMonths],
[Date].[Calendar].[AggregatedMonths],
[SpecificYear],
[Date].[Calendar].[CalcMember]
} ON ROWS
FROM [Adventure Works]
If you'd like all dates (with data) on rows and then various measures on the columns, such as mtd and ytd then you can do something like the following:
With
MEMBER [Measures].[CurrentDay] AS
AGGREGATE(
[Date].[Calendar].Currentmember,
[Measures].[Reseller Sales Amount]
)
MEMBER [Measures].[CurrentMonth] AS
AGGREGATE(
[Date].[Calendar].Currentmember.parent,
[Measures].[Reseller Sales Amount]
)
MEMBER [Measures].[CurrentMTD] AS
AGGREGATE(
MTD([Date].[Calendar].CURRENTMEMBER),
[Measures].[Reseller Sales Amount]
)
MEMBER [Measures].[CurrentYTD] AS
AGGREGATE(
YTD([Date].[Calendar].CURRENTMEMBER),
[Measures].[Reseller Sales Amount]
)
Select
non empty
{
[Measures].[CurrentDay],
[Measures].[CurrentMonth],
[Measures].[CurrentMTD],
[Measures].[CurrentYTD]
}
on columns,
non empty
{
[Date].[Calendar].[Date]
}
having [Measures].[CurrentDay]<>null
on rows
From [Adventure Works]

Resources