Unpivot in postgres with a column created in the same query - postgresql

I am trying to unpivot a table with PostgreSQL as described here.
My problem is that I am creating a new column in my query which I want to use in my cross join lateral statement (which results in an SQL error because the original table does not have this column).
ORIGINAL QUESTION:
select
"Name",
case
when "Year"='2020' then "Date"
end as "Baseline"
from "test_table"
EDIT: I am using the example from the referred StackOverflow question:
create table customer_turnover
(
customer_id integer,
q1 integer,
q2 integer,
q3 integer,
q4 integer
);
INSERT INTO customer_turnover VALUES
(1, 100, 210, 203, 304);
INSERT INTO customer_turnover VALUES
(2, 150, 118, 422, 257);
INSERT INTO customer_turnover VALUES
(3, 220, 311, 271, 269);
INSERT INTO customer_turnover VALUES
(3, 320, 211, 171, 269);
select * from customer_turnover;
creates the following output
customer_id q1 q2 q3 q4
1 100 210 203 304
2 150 118 422 257
3 220 311 271 269
3 320 211 171 269
(I used the customer_id 3 twice because this column is not unique)
Essentially, what I would like to do is the following: I would like to calculate a new column qsum:
select customer_id, q1, q2, q3, q4,
q1+q2+q3+q4 as qsum
from customer_turnover
and use this additional column in my unpivoting statement to produce the following output:
customer_id turnover quarter
1 100 Q1
1 210 Q2
1 203 Q3
1 304 Q4
1 817 qsum
2 150 Q1
2 118 Q2
2 422 Q3
2 257 Q4
2 947 qsum
3 220 Q1
3 311 Q2
3 271 Q3
3 269 Q4
3 1071 qsum
3 320 Q1
3 211 Q2
3 171 Q3
3 269 Q4
3 971 qsum
As I do not want to have qsum in my final output, I understand that I cannot use it in my select statement, but even if I would use it like this
select customer_id, t.*, q1, q2, q3, q4,
q1+q2+q3+q4 as qsum
from customer_turnover c
cross join lateral (
values
(c.q1, 'Q1'),
(c.q2, 'Q2'),
(c.q3, 'Q3'),
(c.q4, 'Q4'),
(c.qsum, 'Qsum')
) as t(turnover, quarter)
I receive the following SQL error: ERROR: column c.qsum does not exist
How can I produce my desired output?

Not sure to well understand your issue, maybe a subquery can help :
select s.baseline
from
( select
"Name",
case
when "Year"='2020' then "Date"
end as "Baseline"
from "test_table"
) AS s

Related

Problem Counting Items For an Individual Row

I need to find the count for ActivityID and AdditionalActivityID for each DailyFieldRecordID based on when GroupID = 260 and ItemID is either 1302,1303,1305,1306. The problem I'm having is that regardless of how many rows for each individual DailyFieldRecordID there are, there can only be one ActivityID and one AdditionalActivityID regardless of how many rows comply with the constraints.
Say someone is filling out a form and they list what their Activity for the day was and also what other activity they might have. They can only list one primary activity(ActivityID) and one secondary activity(AdditionalActivity). But during those activities they could participate with multiple groups(GroupID) or people(ItemID). So when I'm running this query I'm able to separate the rows based on the constraints, but I only want to count how many activities they participated in, which will either be 1 or 2 for each DailyFieldRecordID, regardless of how many groups or people were involved. Right now my query is counting each ActivityID and AdditionalActivityID for each row that meets the criteria, which can give me many more than just 1 or 2 for each DailyFieldRecordID. I'm just not sure how I would go about doing this. Any feedback is greatly appreciated.
DailyFieldRecordID: GroupID: ItemID: ActivityID: AdittionalActivityID:
3369320 260 1302 37 0
3369320 260 1305 37 0
3369320 210 2222 37 0
3369320 250 2222 37 0
3372806 260 1302 56 56
3372806 260 1305 56 56
3372806 250 2222 56 56
3388888 260 2222 45 32
Expected Result:
DailyFieldRecordID: Count:
3369320 1
3372806 2
Current Result:
DailyFieldRecordID: Count:
3369320 2
3372806 4
'
select a.DailyFieldRecordID,
count(case when a.ActivityID <>0 then 1 else null end) +
count(case when a.AdditionalActivityID <>0 then 1 else null end) as count
from AB953 a
where a.GroupID= 260 and exists(
select b.DailyFieldRecordID
from AB953 b
where a.DailyFieldRecordID = b.DailyFieldRecordID and b.ItemID in (1302,1303,1305,1306))
group by DailyFieldRecordID
I get this result when trying your data:
DailyfieldrecordID Count
3369320 3
3372806 2
3388888 1
SELECT DailyFieldRecordID,
COUNT(CASE WHEN ActivityID <>0 then 1 else 0 end +
CASE WHEN AdditionalActivityID <>0 then 1 else 0 end) as Count
from Foo
where GroupID= 260 and exists(
select b.DailyFieldRecordID
from fOO b
where DailyFieldRecordID = b.DailyFieldRecordID and b.ItemID in (1302,1303,1305,1306))
group by DailyFieldRecordID
New query: you might need to fiddle with this, not sure if your data is wrong or not....... cant get it to select 3 and then 2:
SELECT DailyFieldRecordID,
COUNT(CASE WHEN ActivityID <>0 then 1 else 0 end +
CASE WHEN AdditionalActivityID <>0 then 1 else 0 end) as Count
from Foo
where GroupID= 260 and DailyFieldRecordID IN(
select b.DailyFieldRecordID
from fOO b
where b.ItemID IN(1302,1303,1305,1306))
group by DailyFieldRecordID
This should do it:
;WITH CTE AS
(
SELECT A.DailyFieldRecordID
,ActivityID = IIF(A.ActivityID = 0, NULL, A.ActivityID)
,AdittionalActivityID = IIF(A.AdittionalActivityID = 0, NULL, A.AdittionalActivityID)
FROM AB953 A
WHERE A.GroupID = 260
AND A.ItemID IN (1302,1303,1305,1306)
)
SELECT DailyFieldRecordID
,CNT = COUNT(DISTINCT ActivityID) + COUNT(DISTINCT AdittionalActivityID)
FROM CTE
GROUP BY DailyFieldRecordID;
I created this DDL and test data for testing:
DROP TABLE IF EXISTS AB953
GO
CREATE TABLE AB953 (
DailyFieldRecordID INT, GroupID INT, ItemID INT, ActivityID INT, AdittionalActivityID INT)
INSERT INTO AB953
VALUES
( 3369320, 260, 1302, 37, 0 )
,( 3369320, 260, 1305, 37, 0 )
,( 3369320, 210, 2222, 37, 0 )
,( 3369320, 250, 2222, 37, 0 )
,( 3372806, 260, 1302, 56, 56 )
,( 3372806, 260, 1305, 56, 56 )
,( 3372806, 250, 2222, 56, 56 )
,( 3388888, 260, 2222, 45, 32 )
GO

SQL Server - Renumber in Order

I have a table that I need to reorder a column, but I need to keep the original order by date.
TABLE_1
id num_seq DateTimeStamp
fb4e1683-7035-4895-b2c8-d084d9b42ce3 111 08-02-2005
e40e4c3e-65e4-47b7-b13a-79e8bce2d02d 114 10-07-2017
49e261a8-a855-4844-a0ac-37b313da2222 113 01-30-2010
6c4bffb7-a056-4a20-ae1c-5a31bdf683f2 112 04-15-2006
I want to reorder num_seq starting with 1001 through 1004 and keep the numbering in order. So 111 = 1001 and 112 = 1002 and so forth.
This is what I have so far:
DECLARE #num INT
SET #num = 0
UPDATE Table_1
SET #num = num_seq = #id + 1
GO
I know that UPDATE doesn't let me use the keyword ORDER BY. Is there a way to do this in SQL 2008 R2?
Stage the new num_seq in a CTE, then leverage that in your update statement:
declare #Table_1 table (id uniqueidentifier, num_seq int, DateTimeStamp datetime);
insert into #Table_1
values
('fb4e1683-7035-4895-b2c8-d084d9b42ce3', 111, '08-02-2005'),
('e40e4c3e-65e4-47b7-b13a-79e8bce2d02d', 114, '10-07-2017'),
('49e261a8-a855-4844-a0ac-37b313da2222', 113, '01-30-2010'),
('6c4bffb7-a056-4a20-ae1c-5a31bdf683f2', 112, '04-15-2006');
;with stage as
(
select *,
num_seq_new = 1000 + row_number()over(order by DateTimeStamp asc)
from #Table_1
)
update stage
set num_seq = num_seq_new;
select * from #Table_1
Returns:
id num_seq DateTimeStamp
FB4E1683-7035-4895-B2C8-D084D9B42CE3 1001 2005-08-02 00:00:00.000
E40E4C3E-65E4-47B7-B13A-79E8BCE2D02D 1004 2017-10-07 00:00:00.000
49E261A8-A855-4844-A0AC-37B313DA2222 1003 2010-01-30 00:00:00.000
6C4BFFB7-A056-4A20-AE1C-5A31BDF683F2 1002 2006-04-15 00:00:00.000

results mismatched when retrieved dates from column of type character varying

I have two tables,i want to get the min and max date stored in table1 cfrange column which is of type character varying.
table1 and table2 is mapped using sid. i want to get the max and min date range when compared with sid of table2.
table1:
sid cfrange
100 3390
101 8000
102 5/11/2010
103 11/12/2016
104 01/03/2016
105 4000
106 4000
107 03/12/2017
108 03/11/2016
109 4/04/2018
110 10/12/2016
table2:
sid description
102 success
103 success
104 Proceeding
107 success
108 success
I tried as below but its not giving the correct min and max value.Please advice.
select max(t1.cfrange),min(t1.cfrange) from table1 t1,table2 t2 where t1.sid=t2.sid;
You should join two tables and cast cfrange as a date and cross your fingers. (May be you must format it as a date before to cast it).
create table table1 (sid int, cfrange varchar(30));
insert into table1 values
(100, '3390'),
(101, '8000'),
(102, '5/11/2010'),
(103, '11/12/2016'),
(104, '01/03/2016'),
(105, '4000'),
(106, '4000'),
(107, '03/12/2017'),
(108, '03/11/2016'),
(109, '4/04/2018'),
(110, '10/12/2016');
create table table2 (sid int, description varchar(30));
insert into table2 values
(102, 'success'),
(103, 'success'),
(104, 'Proceeding'),
(107, 'success'),
(108, 'success');
select 'Min' as caption, min(cfrange) as value
from (select table1.sid, table1.cfrange::date
from table1
inner join table2
on table1.sid = table2.sid) tt
UNION ALL
select 'Max' as caption, max(cfrange) as value
from (select table1.sid, table1.cfrange::date
from table1
inner join table2
on table1.sid = table2.sid) tt;
caption | value
:------ | :---------
Min | 2010-11-05
Max | 2017-12-03
dbfiddle here

Comparing multiples tables on basis of single column postgresql

I have 3 tables table1,table2,table3.Each having same structure.I want to compare their rows on basis of one column.
structure of tables
table1
country_code country_name rate vendor
91 india 2.0 abc
92 pak 1.0 abc
table2
country_code country_name rate vendor
91 india 2.1 abc1
92 pak 1.1 abc1
93 afgan 1.1 abc1
table3
country_code country_name rate vendor
91 india 2.2 abc2
92 pak 1.2 abc2
93 afgan 1.2 abc2
880 bang 1.2 abc2
desired output is
country_code country_name rate vendor rate vendor rate vendor
91 india 2.0 abc 2.1 abc1 2.2 abc2
92 pak 1.0 abc 1.1 abc1 1.2 abc2
93 afgan 1.1 abc1 1.2 abc2
880 bang 1.2 abc2
I tried full outer join but did not get desired result.
I used this query
SELECT *
FROM table1 a
FULL OUTER JOIN table2 b ON a.country_code=b.country_code
FULL OUTER JOIN table3 c ON c.country_code=a.country_code ;
and result of above query is
91 india 2 91 india 2.1 91 india 2.2
92 pak 1 92 pak 1.1 92 pak 1.2
93 afgan 1.1
880 bang 1.2
93 afgan 1.2
but I want it like
91 india 2 91 india 2.1 91 india 2.2
92 pak 1 92 pak 1.1 92 pak 1.2
93 afgan 1.1 93 afgan 1.2
880 bang 1.2
this should work:
select * from
(
select distinct t3.country_code,
t3.country_name,
t1.rate,
t1.vendor,
t2.rate,
t2.vendor,
t3.rate,
t3.vendor
from (select * from table1 t1 union
select * from table2 t2 union
select * from table3 t3
) allk left join table1 t1 on allk.country_code = t1.country_code
left join table2 t2 on allk.country_code = t2.country_code
left join table3 t3 on allk.country_code = t3.country_code
) a
order by case
when a.country_code like '9%' then 1
else 2
end nulls last;

T-SQL - Several groupings with computation

I need assistance on how I can come up with a query wherein the Table 1 and table 2 will be joined to perform calculation. I have 'cursor' in mind but I am having trouble on conceptualizing. Some kickstart will be a huge help.
basically what I need is something like this:
Table 1:
Rep_Date NumID NumValue Score Period
1/10/2015 1 161 4 Q1
1/11/2015 1 167 2 Q1
1/12/2015 1 95 1 Q1
1/01/2016 1 150 1 Q2
1/02/2016 1 100 2 Q2
1/03/2016 1 600 5 Q2
1/10/2015 38 1 1 Q1
1/11/2015 38 1 2 Q1
1/12/2015 38 1 2 Q1
1/01/2016 38 1 1 Q2
1/02/2016 38 1 2 Q2
1/03/2016 38 1 4 Q2
1/10/2015 113 5 3 Q1
1/11/2015 113 2 4 Q1
1/12/2015 113 8 1 Q1
1/01/2016 113 11 4 Q2
1/02/2016 113 1 5 Q2
1/03/2016 113 5 3 Q2
Table 2
NumID CalculationType
1 SUM
38 SUM
113 AVG
Expected Result:
Rep_Date NumID Result Period
1/10/2015 1 7 Q1
1/01/2016 1 8 Q2
1/10/2015 38 5 Q1
1/01/2016 38 7 Q2
1/10/2015 113 2.67 Q1
1/01/2016 113 4 Q2
Join by NumID to get the calculation type.
Use 'Score' field to derive the result.
Group by NumID, Period
This should work:
declare #t1 table (Rep_Date varchar(50), numId int, numValue int, score int, period varchar(50));
insert into #t1 values
('1/10/2015','1','161','4','Q1'),
('1/11/2015','1','167','2','Q1'),
('1/12/2015','1','95','1','Q1'),
('1/01/2016','1','150','1','Q2'),
('1/02/2016','1','100','2','Q2'),
('1/03/2016','1','600','5','Q2'),
('1/10/2015','38','1','1','Q1'),
('1/11/2015','38','1','2','Q1'),
('1/12/2015','38','1','2','Q1'),
('1/01/2016','38','1','1','Q2'),
('1/02/2016','38','1','2','Q2'),
('1/03/2016','38','1','4','Q2'),
('1/10/2015','113','5','3','Q1'),
('1/11/2015','113','2','4','Q1'),
('1/12/2015','113','8','1','Q1'),
('1/01/2016','113','11','4','Q2'),
('1/02/2016','113','1','5','Q2'),
('1/03/2016','113','5','3','Q2');
declare #t2 table (numId int, CalculationType varchar(50));
insert into #t2 values
('1' ,'SUM'),
('38' ,'SUM'),
('113' ,'AVG')
select
min(t.rep_date) Rep_Date
,t.numId
,case when max(t2.CalculationType) = 'SUM' then sum(t.score)
when max(t2.CalculationType) = 'AVG' then round(avg(1.0 * t.score), 2)
else 0
end Result
,t.period
from
#t1 t
join #t2 t2 on t.numId = t2.numId
group by
t.period, t.numId
order by
numId, period
Output