aliasing pivot column - sql

i am trying to alias the pivot column to scenario1, scenario2, scenario3 instead of 1,2,3. I am getting error.
select *
from (select *
from (select s.campaign_id campaign_id, s.scenario_index scenario_index
from scenario s, campaign c where s.campaign_id = c.campaign_id)
pivot (max(scenario_index)for scenario_index in (1,2,3))
)a
thank you, aggregation gives the result with alias now. The requirement i have is to combine these columns with another query which is
select CASE WHEN AWARD_TYPE = 0 THEN award_rate||' points'
when AWARD_TYPE = 1 then Award_rate||' %'
when award_type=2 then RATIO_POINTS||' points per '||RATIO_MON_UNIT||' AED' End
from points_rule p
where c.pt_basic_rule_id = p.point_rule_id ) as pool_awards,
this query comes as a column and then the scenario1, 2,3 should come as 3 columns with the value of the pool_award based on the campaign_id

Just use conditional aggregation:
select s.campaign_id,
max(case when scenario_index = 1 then 1 end) as scenario1,
max(case when scenario_index = 2 then 1 end) as scenario2,
max(case when scenario_index = 3 then 1 end) as scenario3
from scenario s join
campaign c
on s.campaign_id = c.campaign_id
group by campaign_id;

You can use an alias in IN clause of the PIVOT as follows:
select *
from (select *
from (select s.campaign_id campaign_id, s.scenario_index scenario_index
from scenario s, campaign c where s.campaign_id = c.campaign_id)
pivot (max(scenario_index)for scenario_index in (1 as scenario1,2 as scenario2,3 as scenario3))
)a

Related

How to calculate Total records Counts in table with my scenario

I am Writing a SQL Code which basically count stars values Like ratings Feedback forms.To calculate how many peoples rate
1 star,2,3 and so on i am using pivot unpivot SQL properties to calculate count against of each number hits.Now i want to calculate count of all records in the table along with my this query.
i want to achieve my desire result without sub-query.
WITH survey AS (
SELECT
*
FROM
(
SELECT
student_id,
performance,
teacher_behaviour,
survey_id
FROM
survey_feedback
WHERE
survey_id = 1
GROUP BY
student_id,
performance,
teacher_behaviour,
survey_id
) UNPIVOT ( star
FOR q
IN ( performance AS 'PERFORMANCE',
teacher_behaviour AS 'TEACHER_BEHAVIOUR'
) )
ORDER BY
1,
2
)
SELECT
*
FROM
survey PIVOT (
COUNT ( student_id )
FOR star
IN ( 1, 2, 3, 4, 5 )
)
ORDER BY
q;
enter image description here
Hmmm . . . I'm not a fan of PIVOT and UNPIVOT. They really offer no new functionality and are quite bespoke and not powerful enough.
So, I would just unpivot and use conditional aggregation:
SELECT survey_id, which, COUNT(rating) as total,
SUM(CASE WHEN rating = 1 THEN 1 ELSE 0 END) as rating_1,
SUM(CASE WHEN rating = 2 THEN 1 ELSE 0 END) as rating_2,
SUM(CASE WHEN rating = 3 THEN 1 ELSE 0 END) as rating_3,
SUM(CASE WHEN rating = 4 THEN 1 ELSE 0 END) as rating_4,
SUM(CASE WHEN rating = 5 THEN 1 ELSE 0 END) as rating_5
FROM (SELECT sf.*,
(CASE WHEN which = 'PERFORMANCE' THEN performance
WHEN which = 'TEACHER_BEHAVIOUR' THEN teacher_behavior
END) as rating
FROM survey_feedback sf CROSS JOIN
(SELECT 'PERFORMANCE' as which FROM DUAL UNION ALL
SELECT 'TEACHER_BEHAVIOUR' FROM DUAL
) n
) sf
WHERE sf.survey_id = 1
GROUP BY sf.survey_id, which;
In Oracle 12C+, I would use a lateral join for unpivoting.

Get single row depending of conditional

I have a simple select query with some joins like:
SELECT
[c].[column1]
, [c].[column2]
FROM [Customer] AS [c]
INNER JOIN ...
So I do a left join with my principal table as:
LEFT JOIN [Communication] AS [com] ON [c].[CustomerGuid] = [com].[ComGuid]
this relatioship its 1 to *, one customer can have multiple communications
So in my select I want to get value 1 or 2 depending of condition:
Condition:
if ComTypeKey (from communication) table have a row with value 3 and have another row with vale 4 return 1 then 0
So I try something like:
SELECT
[c].[column1]
, [c].[column2]
, IIF([com].[ComTypeKey] = 3 AND [com].[ComTypeKey] = 4,1,0)
FROM [Customer] AS [c]
INNER JOIN ...
LEFT JOIN [Communication] AS [com] ON [c].[CustomerGuid] = [com].[ComGuid]
But it throws me two rows, beacause there are 2 rows on communication. My desire value is to get only one row with value 1 if my condition is true
If you have multiple rows you need GROUP BY, then count the relevant keys and subtract 1 to get (1, 0)
SELECT
[c].[column1]
, [c].[column2]
, COUNT(CASE WHEN [ComTypeKey] IN (3,4) THEN 1 END) - 1 as FLAG_CONDITION
FROM [Customer] AS [c]
INNER JOIN ...
LEFT JOIN [Communication] AS [com]
ON [c].[CustomerGuid] = [com].[ComGuid]
GROUP BY
[c].[column1]
, [c].[column2]
I'm not really sure I understand.
This will literally find if both values 3 and 4 exist for that CustomerGuid, and only select one of them in that case - not filtering out any record otherwise.
If this is not what you want, providing sample data with the expected result would remove the ambiguity.
SELECT Field1,
Field2,
...
FieldN
FROM (SELECT TMP.*,
CASE WHEN hasBothValues = 1 THEN
ROW_NUMBER() OVER ( PARTITION BY CustomerGuid ORDER BY 1 )
ELSE 1
END AS iterim_rn
FROM (SELECT TD.*,
MAX(CASE WHEN Value1 = '3' THEN 1 ELSE 0 END) OVER
( PARTITION BY CustomerGuid ) *
MAX(CASE WHEN Value1 = '4' THEN 1 ELSE 0 END) OVER
( PARTITION BY CustomerGuid ) AS hasBothValues
FROM TEST_DATA TD
) TMP
) TMP2
WHERE interim_rn = 1

Select the records that have some value but at the same time have not other value

Before starting, thank you for your help.
My problem is: I have a table, for example, activity_records, that has a date column and a activity_id column.
I want to select only those dates that, for example, have the activity_id value of 1 but do not have the value of 2 in any of the other records having the same date.
I have tried multi-select queries and all that.
One method uses not exists:
select ar.*
from activity_records ar
where ar.activity_id = 1 and
not exists (select 1
from activity_records ar2
where r2.date = ar.date and ar2.activity_id = 2
);
Because you only want dates, an alternative is group by:
select ar.date
from activity_records ar
group by ar.date
having sum(case when ar.activity_id = 1 then 1 else 0 end) > 0 and
sum(case when ar.activity_id = 2 then 1 else 0 end) = 0;
Or, most simply for this particular case:
select ar.date
from activity_records ar
where ar.activity_id in (1, 2)
group by ar.date
having max(ar.activity_id) = 1 ;
SELECT [date] FROM [activity_records] WHERE [activity_id] = 1
EXCEPT
SELECT [date] FROM [activity_records] WHERE [activity_id] = 2
See also WHERE NOT EXISTS and APPLY for more complicated scenarios.
Another way is to take only those dates with one distinct activity_id against it and then filtering those dates with activity_id = 1 by a self join.
SELECT DISTINCT B.DATE
FROM
(SELECT DATE, COUNT(DISTINCT ACTIVITY) AS COUNT_ACTIVITIES
FROM YOUR_TABLE
GROUP BY DATE
HAVING COUNT(DISTINCT ACTIVITY) = 1) A
INNER JOIN
YOUR_TABLE B
ON A.DATE = B.DATE
AND B.ACTIVITY_ID = 1;
One method using not in :
select ar.* from activity_records ar where ar.activity_id = 1 and ar.date not in (select ar2.date from activity_records ar2 where ar2.activity_id = 2 );

Display SQL Data From Row to Column

My SQL statement is list as below:
SELECT Count(DISTINCT A.LM_PERSON_ID) AS HEAD_COUNT
,A.LM_STATUS
,To_Char(A.LM_STATUS_CHANGE_DT,'YYYY') AS YEAR
,B.LM_COURSE_NAME AS COURSE_NAME
FROM LM_ENRLOLMENT A
,LM_COURSE_TBL B
WHERE A.LM_STATUS='COMP'
AND A.LM_COURSE_ID=B.LM_CI_ID
GROUP BY A.LM_STATUS_CHANGE_DT,LM_STATUS,B.LM_COURSE_NAME
The example output I would like to display was:
COURSE_NAME 2010 2011 2012
A 4 5 1
B 2 1 1
C 6 0 3
D 1 1 2
But the main problem I am facing is that LM_STATUS_CHANGE_DT is dynamic data. Is there anyone that can show me how I could do this?
You did not specify what RDBMS you are using but you should be able to use the following in all versions:
SELECT
B.LM_COURSE_NAME AS COURSE_NAME,
count(DISTINCT case when To_Char(A.LM_STATUS_CHANGE_DT,'YYYY') = '2010' then A.LM_PERSON_ID end) as Year2010,
count(DISTINCT case when To_Char(A.LM_STATUS_CHANGE_DT,'YYYY') = '2011' then A.LM_PERSON_ID end) as Year2011,
count(DISTINCT case when To_Char(A.LM_STATUS_CHANGE_DT,'YYYY') = '2012' then A.LM_PERSON_ID end) as Year2012
FROM LM_ENRLOLMENT A
INNER JOIN LM_COURSE_TBL B
ON A.LM_COURSE_ID=B.LM_CI_ID
WHERE A.LM_STATUS='COMP'
GROUP BY B.LM_COURSE_NAME
If you are using an RDBMS that has the PIVOT function (SQL Server 2005+/Oracle 11g+) then your code will be similar to this:
SELECT *
FROM
(
SELECT DISTINCT B.LM_COURSE_NAME,
To_Char(A.LM_STATUS_CHANGE_DT,'YYYY') As Year,
A.LM_PERSON_ID
FROM LM_ENRLOLMENT A
INNER JOIN LM_COURSE_TBL B
ON A.LM_COURSE_ID=B.LM_CI_ID
WHERE A.LM_STATUS='COMP'
) src
PIVOT
(
count(LM_PERSON_ID)
for Year in ('2010', '2011', '2012')
) piv

How to combine two selects with different where clauses?

select kota ,total, totalsum from
(
SELECT i.[Antam_Unit] as kota ,count(p.[Id_Pks_Pk])as total FROM [SIMPKBL].[dbo].[Pks_Pk] p join [SIMPKBL].[dbo].[Par_Unit_Antam] i on i.Id_Unit_Antam = p.Id_Unit_Antam group by i.[Id_Unit_Antam],i.Antam_Unit
UNION ALL
SELECT i.[Antam_Unit] as kota , count(p.[Id_Proposal_Pk])as totalsum FROM [SIMPKBL].[dbo].[Pks_Pk] p join [SIMPKBL].[dbo].[Par_Unit_Antam] i on i.Id_Unit_Antam = p.Id_Unit_Antam where YEAR(p.Tanggal_Cetak_Pks_Pk) = '2012' group by i.[Id_Unit_Antam],i.Antam_Unit
) t
group by kota,total
I want an output like this:
kota total totalsum
A 12 4
B 16 5
Since the queries are so similar it appears that they can be combined into one select:
select i.[Antam_Unit] as kota,
count(p.[Id_Pks_Pk]) as total,
count( case when YEAR(p.Tanggal_Cetak_Pks_Pk) = '2012' then p.[Id_Proposal_Pk] else null end ) as totalsum
FROM [SIMPKBL].[dbo].[Pks_Pk] p join [SIMPKBL].[dbo].[Par_Unit_Antam] i on i.Id_Unit_Antam = p.Id_Unit_Antam
group by i.[Id_Unit_Antam], i.Antam_Unit
If I understood your requirements correctly, the result you are looking for can be achieved using this simple statement:
SELECT i.[Antam_Unit] as kota,
count(p.[Id_Pks_Pk]) as total,
SUM(CASE WHEN YEAR(p.Tanggal_Cetak_Pks_Pk) = '2012' AND p.[Id_Proposal_Pk] IS NOT NULL THEN 1 ELSE 0 END) as totalsum
FROM [SIMPKBL].[dbo].[Pks_Pk] p
join [SIMPKBL].[dbo].[Par_Unit_Antam] i
on i.Id_Unit_Antam = p.Id_Unit_Antam
group by i.[Id_Unit_Antam],i.Antam_Unit