Why am I getting the same output from different codes? - database

So, I've been learning MDX and I came across some basic data querying along multiple dimensions.
The concept of tuples and sets are kind of clear for me.
What's the query supposed to do: show a measure across multiple dimensions
Code 1:
Select
Non Empty
{[Measures].[name of measure]}
On Columns,
Non Empty
{
(
[Table 0].[Hierarchy 0].&[Member 0] *
[Table 1].[Hierarchy 1].Children *
[Table 2].[Hierarchy 2].Children *
[Table 2].[Hierarchy 3].Children *
{ [Table 3].[Hierarchy 4].&[Member 1],
[Table 3].[Hierarchy 4].&[Member 2],
[Table 3].[Hierarchy 4].&[Member 3],
[Table 3].[Hierarchy 4].&[Member 4],
[Table 3].[Hierarchy 4].&[Member 5]
}
)
}
On Rows
From [DB]
Description: On columns, there's a set followed by a big tuple with multiple cross joins. I explicitly select some members in order to filter them.
Code 2:
Select
Non Empty
{[Measures].[name of measure]}
On Columns,
Non Empty
(
{[Table 0].[Hierarchy 0].&[Member 0]} *
( { [Table 1].[Hierarchy 1].Children } *
( { [Table 2].[Hierarchy 2].Children } *
( { [Table 2].[Hierarchy 3].Children } *
{[Table 3].[Hierarchy 4].&[Member 1],
[Table 3].[Hierarchy 4].&[Member 2],
[Table 3].[Hierarchy 4].&[Member 3],
[Table 3].[Hierarchy 4].&[Member 4],
[Table 3].[Hierarchy 4].&[Member 5]}
)
)
)
)
On Rows
From [DB]
Description: Nested tuples and sets.
I've got the first code from my mind and the 2nd one from a query generator. They both give me the same output, but I can't get my head wrapped around the concept on the 2nd one. Why are there so many tuples and sets?
Which would be the optimal version?

Related

Merge data from two tables horizontally

I have data coming from two source table "T" & "S" as below
I want to merge the data horizontally from two tables and show the result as below
Column name in Result are fixed where
D1,D2,D3 are date column that shows last 3 max(TDATE) after merging data from table T & S for each group "Code"
TID1,TID2,TID3 are ID
from table T for Date D1,D2,D3
SID1,SID2,SID3 are ID from table S for
Date D1,D2,D3
My below query is returning result
WITH L1 AS
(
SELECT NULL AS TID, SID, CODE, TDATE
FROM (VALUES
('S1','A','2001-01-01'),
('S3','A','2001-01-03'),
('S5','B','2001-01-05')
) V(SID,CODE,TDATE)
UNION ALL
SELECT TID, NULL AS SID, CODE, TDATE
FROM (VALUES
('T1','A','2001-01-01'),
('T2','A','2001-01-02'),
('T5','B','2001-01-05')
) V(TID,CODE,TDATE)
)
,L2 AS
(
SELECT SID,TID,CODE,[TDATE],
DENSE_RANK () over (
partition by CODE
order by [TDATE] desc
) RNO
FROM L1
)
,L3 AS
(
SELECT MAX(TID) AS TID,MAX(SID) AS SID,CODE,TDATE,MAX(RNO)AS RNO
FROM L2
GROUP BY CODE,TDATE,RNO
HAVING MAX(RNO)<=3
)
SELECT * FROM L3
Now if I replace the last line of the query "Select * from L3" with the below query that pivot the result horizontally I am getting the correct result.
SELECT
R1.CODE
,R1.TID AS TID1,R2.TID AS TID2,R3.TID AS TID3
,R1.SID AS SID1,R2.SID AS SID2,R3.SID AS SID3
,R1.TDATE AS D1 , R2.TDATE AS D2 , R3.TDATE AS D3
FROM L3 R1
LEFT OUTER JOIN L3 R2 ON R1.RNO+1=R2.RNO AND R1.CODE=R2.CODE
LEFT OUTER JOIN L3 R3 ON R1.RNO+2=R3.RNO AND R1.CODE=R3.CODE
where R1.RNO=1
The problem is the above query is very slow when I have to run it with thousands of record in Table T & S with the last 5 dates in column D1,D2,D3,D4,D5
Is there any other way to optimise this query or a new query that can run fast?
I tried to add indexes on table T & S as below
The primary Key On T(TID) & S(SID)
Index on T(Code,TDATE)
Index on T(TDATE)
Index on S(Code,TDATE)
Index on S(TDATE)
Total rows in Table T & S are approx 50K each and the query is still running after 6 mins
Here is a link for an execution plan for the actual query that is very slow
Execution Plan of actual slow query
I think you are killing performance by doing the joins in your last select.
What about trying a pivot operation instead? Replace the select with:
SELECT
CODE
,Max(IIF(rno = 1, TID, NULL)) Tid1
,Max(IIF(rno = 2, TID, NULL)) Tid2
,Max(IIF(rno = 3, TID, NULL)) Tid3
,Max(IIF(rno = 1, SID, NULL)) Sid1
,Max(IIF(rno = 2, SID, NULL)) Sid2
,Max(IIF(rno = 3, SID, NULL)) Sid3
,Max(IIF(rno = 1, Tdate, NULL)) D1
,Max(IIF(rno = 2, Tdate, NULL)) D2
,Max(IIF(rno = 3, Tdate, NULL)) D3
FROM L3
GROUP BY Code

Sum of index space :: T-SQL vs GUI

I have recently rebuilt all indexes on a table and the GUI from SSMS tells me that the index space is 7 555.711 MB.
But if I look at the actual index space through T-SQL I have a different result:
SELECT tn.[name] AS [Table name], ix.[name] AS [Index name],
SUM(sz.[used_page_count]) * 8 * 1024/(1024 * 1024) AS [Index size (MB)]
FROM sys.dm_db_partition_stats AS sz
INNER JOIN sys.indexes AS ix ON sz.[object_id] = ix.[object_id]
AND sz.[index_id] = ix.[index_id]
INNER JOIN sys.tables tn ON tn.OBJECT_ID = ix.object_id
where tn.[name] = 'MyTableName'
GROUP BY tn.[name], ix.[name]
ORDER BY tn.[name]
Why?
Thank you #Jeroen Mostert,
In fact the cluster index is part of the table data.
With Index Space SSMS is calculating only the non-clustered index which are:
1452 + 1590 + 1590 + 1452 + 1452 = 7536MB
which is very close to 7555MB

SQL join to an alias column name in SQL Server

Not sure if this is possible but I'm trying to join to an alias column in SQL Server.
Is it possible to change the JOIN below?
JOIN
#LOGFILE ON #CSIQUESTIONLOG.LogSeqNo = #LOGFILE.Seq
AND #LOGFILE.Contcode = 'WCM'
to
JOIN
#LOGFILE ON #CSIQUESTIONLOG.LogSeqNo = #LOGFILE.[SEQ2]
AND #LOGFILE.Contcode = 'WCM'
So it joins to the SEQ2 column - not the SEQ column, and so I only have to run one query
Sample data below:
IF OBJECT_ID('tempdb..#CSIQUESTIONLOG') IS NOT NULL
DROP TABLE #CSIQUESTIONLOG
SELECT *
INTO #CSIQUESTIONLOG
FROM (VALUES ('BA', '2017-01-01','123451', '185', 2),
('BA', '2017-01-01','123452', '185', 4),
('BA', '2017-01-01','123453', '184', 1),
('BA', '2017-01-01','123454', '183', 3),
('BA', '2017-01-01','123455', '182', 5),
('BA', '2017-01-01','123456', '181', 0),
('BA', '2017-01-01','123457', '182', 1),
('BA', '2017-01-01','7684417', '180', 2)) d (Dealer, Created, Logseqno, CSIseqno, Answer)
IF OBJECT_ID('tempdb..#LOGFILE') IS NOT NULL
DROP TABLE #LOGFILE
SELECT *
INTO #LOGFILE
FROM (VALUES (7684417, 'BA', 498, 'WCM', 1261723),
(7669984, 'BA', 38, 'CSI', 1261723),
(7685141, 'BA', 400, 'WCM', 1261750),
(7686369, 'BA', 193, 'CSI', 1261750),
(7692571, 'BA', 401, 'WCM', 1262289),
(7700336, 'BA', 38, 'CSI', 1262289)) d (Seq, Dealer, OpNum, Contcode, ContSeqNo)
SELECT
a.*, x.Seq AS [SEQ2]
FROM
#LOGFILE a
OUTER APPLY
(SELECT Seq
FROM #LOGFILE b
WHERE b.ContSeqNo = a.ContSeqNo AND b.ContCode = 'CSI') x
Final query:
SELECT
#CSIQUESTIONLOG.Created, #CSIQUESTIONLOG.CSIseqno,
#LOGFILE.OpNum,
COUNT (*) AS TOTAL
FROM
#CSIQUESTIONLOG
JOIN
#LOGFILE ON #CSIQUESTIONLOG.LogSeqNo = #LOGFILE.Seq
AND #LOGFILE.Contcode = 'WCM'
GROUP BY
#CSIQUESTIONLOG.Created, #CSIQUESTIONLOG.CSIseqno, #LOGFILE.OpNum
Firstly, in your final query there ins no column Seq2. Those are two seperate queries, and thus, they can't interact with each other.
Without the expected result set, I've just chanegd the SQL to what I believe you're after. If it's not, post your expected result set.
SELECT QL.Created,
QL.CSIseqno,
LF2.OpNum, --Not sure if this should be LF1, or LF2. Guessed 2
COUNT (*) AS TOTAL
FROM #CSIQUESTIONLOG QL
JOIN #LOGFILE LF1 ON QL.LogSeqNo = LF1.Seq AND LF1.Contcode = 'WCM'
JOIN #LOGFILE LF2 ON LF1.ContSeqNo = LF2.ContSeqNo AND LF2.ContCode = 'CSI'
GROUP BY QL.Created, --You were completely missing your GROUP BY
QL.CSIseqno,
LF2.OpNum;

Struggling with conditional logic

EDITED QUESTIONS:
I can't seem to figure out the conditional logic for my query.
I am certain that this is simple but I have been spinning my wheels on this one for too long - it is just one of those days.
Any help is always appreciated.
CURRENT QUERY:
SELECT
r.WidgetPK
,r.WidgetName
,r.WeightRateFlag [WeightRateFlag]
,r.Rate [Rate]
,r.Breakpoint [Breakpoint]
,MAX(ISNULL(f.ShippingFee,0)) [ShippingFee]
,MAX(ISNULL(f.OtherFee,0)) [OtherFee]
,MAX(r.weight) [Weight]
FROM
#Rates r
LEFT JOIN #Fees f ON f.WidgetPK = r.WidgetPK
I left out the GROUP BY for simplicity.
If the WeightRateFlag has a 1 in it in ANY row for each WidgetPK then all rows with a 0 will not be returned. If the WeightRateFlag has no rows with a 1 in it then ALL rows will be returned.
Sorry the original question wasn't clear - searches aren't helping and I asked a coworker. I think my problem may just be that I am asking the wrong question here and in my searches.
SELECT
r.WidgetPK
,r.WidgetName
,r.WeightRateFlag [WeightRateFlag]
,r.Rate [Rate]
,r.Breakpoint [Breakpoint]
,MAX(ISNULL(f.ShippingFee,0)) [ShippingFee]
,MAX(ISNULL(f.OtherFee,0)) [OtherFee]
,MAX(r.weight) [Weight]
FROM
#Rates r
LEFT JOIN #Fees f ON f.WidgetPK = r.WidgetPK
WHERE r.WeightRateFlag = 1
UNION ALL
SELECT
r.WidgetPK
,r.WidgetName
,r.WeightRateFlag [WeightRateFlag]
,r.Rate [Rate]
,r.Breakpoint [Breakpoint]
,MAX(ISNULL(f.ShippingFee,0)) [ShippingFee]
,MAX(ISNULL(f.OtherFee,0)) [OtherFee]
,MAX(r.weight) [Weight]
FROM
#Rates r
LEFT JOIN #Fees f ON f.WidgetPK = r.WidgetPK
WHERE r.WeightRateFlag = 0
AND NOT EXISTS (SELECT * FROM #rates r2 WHERE r2WeightRateFlag =1 AND r.WidgetName = r2.WidgetName)
A bit convoluted-looking, but CTEs can be extremely helpful. Plus they should work pretty well with the optimizer. Modify for the columns you need.
/* TEST DATA SETUP */
IF OBJECT_ID(N'tempdb..#t1') IS NOT NULL
BEGIN
DROP TABLE #t1
END
CREATE TABLE #t1 (WidgetPK int, col1 varchar(19), WeightRateFlag bit, ShippingFee money, OtherFee money, [Weight] int);
INSERT INTO #t1 (WidgetPK, col1, WeightRateFlag, ShippingFee, OtherFee, [Weight])
VALUES
(1, 'showme1', 1, 9, 1, 1)
, (1, 'noshow2', 0, 2, 9, 2)
, (1, 'noshow3', 0, 1, 2, 9)
, (2, 'showme1', 1, 9, 9, 9)
, (3, 'showme1', 0, 1, 9, 1)
, (3, 'showme2', 0, 9, 9, 9)
, (3, 'showme3', 0, 9, 1, 9)
;
/* QUERY STARTS HERE */
WITH cte1 AS (
SELECT x1.*
FROM (
SELECT #t1.WidgetPK, #t1.col1, #t1.WeightRateFlag, #t1.ShippingFee, #t1.OtherFee, #t1.[Weight]
, RANK() OVER (PARTITION BY #t1.WidgetPK ORDER BY #t1.WeightRateFlag DESC) AS rn
FROM #t1
) x1 WHERE x1.rn = 1
)
, cte2 AS (
SELECT cte1.WidgetPK
, MAX(cte1.ShippingFee) AS ShippingFee
, MAX(cte1.OtherFee) AS OtherFee
, MAX(cte1.[Weight]) AS [Weight]
FROM cte1
GROUP BY cte1.WidgetPK
)
SELECT cte1.WidgetPK, cte1.col1, cte1.WeightRateFlag, cte2.ShippingFee, cte2.OtherFee, cte2.[Weight]
FROM cte1
LEFT OUTER JOIN cte2 ON cte1.WidgetPK = cte2.WidgetPK
;

(SQL) Query Results on one row

So I have two tables, named "Questions" and Answers
I made a INNER JOIN for those two tables
SELECT Questions.ID, Questions.QText, Answers.AText
FROM Questions INNER JOIN Answers
ON Questions.ID=Answers.QuestionID;
And the result looks like this:
However, you can clearly see, that the question is displayed 4 times each time with on of the answers.
Now My question is: Is it possible to have the result in one row, consisting of
[ID] - [Question] - [Answer1] - [Answer2] - [Answer3] - [Answer4]
Use CROSS APPLY for CSV. Don't do it inline, then you need a grouping...
SELECT q.ID, q.QText, Answers = STUFF(x.csv, 1, 1, '')
FROM Questions q
CROSS APPLY
(
SELECT
'-' + a.Atext
FROM
Answers a
WHERE
a.QuestionID = q.ID
FOR XML PATH ('')
) x (csv)
You could use this Query for a Pivot:
SELECT QID, QText, [1], [2], [3], [4]
FROM (SELECT Q.ID AS QID, A.ID AS AID, Q.QText, A.AText FROM Questions AS Q
INNER JOIN Answers AS A ON Q.ID = A.QuestionID) QA
PIVOT
(
MAX(AText)
FOR AID
IN ([1], [2], [3], [4])
) AS PV
BUT: You must use a combined Primary Key for your Answer Table.
With this Pivot Table the answer ID must be 1, 2, 3, 4 every time. Otherwise you don't get your answers.
FOR AID declares, which column is used for this.
Otherwise you could add a column to answers which called "AnswerNr" or something like that. In this column you put 1 to 4 for your answers and change the query to:
SELECT QID, QText, [1], [2], [3], [4]
FROM (SELECT Q.ID AS QID, ->A.AnswerNr<-, Q.QText, A.AText FROM Questions AS Q
INNER JOIN Answers AS A ON Q.ID = A.QuestionID) QA
PIVOT
(
MAX(AText)
FOR ->AnswerNr<-
IN ([1], [2], [3], [4])
) AS PV
To get the Question with all it's answers on single row Use COALESCE:
DECLARE #Answer VARCHAR(8000)
SELECT Questions.ID, Questions.QText, #Answer = COALESCE(#Answer + ', ', '') + AText
FROM Questions INNER JOIN Answers ON Questions.ID=Answers.QuestionID
WHERE AText IS NOT NULL
If you're using SQL Server 2005, you could use the FOR XML PATH command.
SELECT Questions.ID, Questions.QText,
(STUFF((SELECT CAST(', ' + [AText] AS VARCHAR(MAX))
FROM Answers
WHERE Questions.ID = Answers.QuestionID
FOR XML PATH ('')), 1, 2, '')) AS Answers
FROM Questions

Resources