Report an amount field by a value in another field - postgresql

I have a large table that has a structure something like the following:
Create Table public.example
(
id character varying(7) ,
type character varying(1) ,
amount decimal ,
date1 date ,
plan character varying(2) ,
date2 date );
Insert into public.example
( Id,Type,Amount,Date1,Plan,Date2)
values
( '1343657' , 'e',235.26 ,'2021-01-03', 'HS', '2021-07-03'),
( '1343657' , 's',6234.25,'2021-01-15', 'RT', '2021-05-09'),
( '1343657' , 's',235.26 ,'2021-01-05', 'HS', '2021-05-03'),
( '1343657' , '3',235.26 ,'2021-01-05', 'HS', '2021-05-17'),
( '1343657' , 's',235.26 ,'2021-01-05', 'HS', '2021-03-19'),
( '5364324' , 'e',1245.90,'2021-01-17', 'MM', '2021-04-23'),
( '5364324' , '1',5285.88,'2021-01-14', 'MM', '2021-02-28'),
( '5364324' , 'e',1245.10,'2021-01-08', 'VI', '2021-06-30'),
( '5364324' , 'e',7452.05,'2021-01-10', 'DT', '2021-03-07') ;
I need to list the "amount" field across the report in different buckets based on the value of the “Plan” field. I also need to summarize the amount by Id and Type. My method doesn’t work because it adds another required Group BY and I don’t get a summarized amount by Id and Type.
Select id,type,
case When a.plan ='HS' then sum(amount) else 0 end as "HS",
case When a.plan ='RT' then sum(amount) else 0 end as "RT",
case When a.plan ='MM' then sum(amount) else 0 end as "MM",
case When a.plan ='VI' then sum(amount) else 0 end as "VI",
case When a.plan ='DT' then sum(amount) else 0 end as "DT"
from public.example a
where date2>='2021-01-01' and date2<='2021-12-31'
group by 1,2,a.plan
The perfect solution would allow me to add date1 to the Select output as well.
Select OUTPUT
Thx

Related

Postgresql, set order by desc or asc depending on variable parse into function

I have a function that takes product pricing data from today and yesterday and works out the difference, orders it by price_delta_percentage and then limits to 5. Now currently I order by price_delta_percentage DESC which returns the top 5 products that have increased in price since yesterday.
I would like to parse in a variable - sort - to change the function to either sort by DESC, or ASC. I have tried to use IF statements and get syntax errors and CASE statements which states that price_delta_percentage doesn't exist.
Script:
RETURNS TABLE(
product_id varchar,
name varchar,
price_today numeric,
price_yesterday numeric,
price_delta numeric,
price_delta_percentage numeric
)
LANGUAGE 'sql'
COST 100
STABLE STRICT PARALLEL SAFE
AS $BODY$
WITH cte AS (
SELECT
product_id,
name,
SUM(CASE WHEN rank = 1 THEN trend_price ELSE NULL END) price_today,
SUM(CASE WHEN rank = 2 THEN trend_price ELSE NULL END) price_yesterday,
SUM(CASE WHEN rank = 1 THEN trend_price ELSE 0 END) - SUM(CASE WHEN rank = 2 THEN trend_price ELSE 0 END) as price_delta,
ROUND(((SUM(CASE WHEN rank = 1 THEN trend_price ELSE NULL END) / SUM(CASE WHEN rank = 2 THEN trend_price ELSE NULL END) - 1) * 100), 2) as price_delta_percentage
FROM (
SELECT
magic_sets_cards.name,
pricing.product_id,
pricing.trend_price,
pricing.date,
RANK() OVER (PARTITION BY product_id ORDER BY date DESC) AS rank
FROM pricing
JOIN magic_sets_cards_identifiers ON magic_sets_cards_identifiers.mcm_id = pricing.product_id
JOIN magic_sets_cards ON magic_sets_cards.id = magic_sets_cards_identifiers.card_id
JOIN magic_sets ON magic_sets.id = magic_sets_cards.set_id
WHERE date BETWEEN CURRENT_DATE - days AND CURRENT_DATE
AND magic_sets.code = set_code
AND pricing.trend_price > 0.25) p
WHERE rank IN (1,2)
GROUP BY product_id, name
ORDER BY price_delta_percentage DESC)
SELECT * FROM cte WHERE (CASE WHEN price_today IS NULL OR price_yesterday IS NULL THEN 'NULL' ELSE 'VALID' END) !='NULL'
LIMIT 5;
$BODY$;sql
CASE Statement:
ORDER BY CASE WHEN sort = 'DESC' THEN price_delta_percentage END DESC, CASE WHEN sort = 'ASC' THEN price_delta_percentage END ASC)
Error:
ERROR: column "price_delta_percentage" does not exist
LINE 42: ORDER BY CASE WHEN sort = 'DESC' THEN price_delta_percenta...
You can't use CASE to decide between ASC and DESC like that. Those labels are not data, they are part of the SQL grammar. You would need to do it by combining the text into a string and then executing the string as a dynamic query, which means you would need to use pl/pgsql, not SQL
But since your column is numeric, you could just order by the product of the column and an indicator variable which is either 1 or -1.

SQL Server - Select with Group By together Raw_Number

I'm using SQL Server 2000 (80). So, it's not possible to use the LAG function.
I have a code a data set with four columns:
Purchase_Date
Facility_no
Seller_id
Sale_id
I need to identify missing Sale_ids. So every sale_id is a 100% sequential, so the should not be any gaps in order.
This code works for a specific date and store if specified. But i need to work on entire data set looping looping through every facility_id and every seller_id for ever purchase_date
declare #MAXCOUNT int
set #MAXCOUNT =
(
select MAX(Sale_Id)
from #table
where
Facility_no in (124) and
Purchase_date = '2/7/2020'
and Seller_id = 1
)
;WITH TRX_COUNT AS
(
SELECT 1 AS Number
union all
select Number + 1 from TRX_COUNT
where Number < #MAXCOUNT
)
select * from TRX_COUNT
where
Number NOT IN
(
select Sale_Id
from #table
where
Facility_no in (124)
and Purchase_Date = '2/7/2020'
and seller_id = 1
)
order by Number
OPTION (maxrecursion 0)
My Dataset
This column:
case when
Sale_Id=0 or 1=Sale_Id-LAG(Sale_Id) over (partition by Facility_no, Purchase_Date, Seller_id)
then 'OK' else 'Previous Missing' end
will tell you which Seller_Ids have some sale missing. If you want to go a step further and have exactly your desired output, then filter out and distinct the 'Previous Missing' ones, and join with a tally table on not exists.
Edit: OP mentions in comments they can't use LAG(). My suggestion, then, would be:
Make a temp table that that has the max(sale_id) group by facility/seller_id
Then you can get your missing results by this pseudocode query:
Select ...
from temptable t
inner join tally N on t.maxsale <=N.num
where not exists( select ... from sourcetable s where s.facility=t.facility and s.seller=t.seller and s.sale=N.num)
> because the only way to "construct" nonexisting combinations is to construct them all and just remove the existing ones.
This one worked out
; WITH cte_Rn AS (
SELECT *, ROW_NUMBER() OVER(PARTITION BY Facility_no, Purchase_Date, Seller_id ORDER BY Purchase_Date) AS [Rn_Num]
FROM (
SELECT
Facility_no,
Purchase_Date,
Seller_id,
Sale_id
FROM MyTable WITH (NOLOCK)
) a
)
, cte_Rn_0 as (
SELECT
Facility_no,
Purchase_Date,
Seller_id,
Sale_id,
-- [Rn_Num] AS 'Skipped Sale'
-- , case when Sale_id = 0 Then [Rn_Num] - 1 Else [Rn_Num] End AS 'Skipped Sale for 0'
, [Rn_Num] - 1 AS 'Skipped Sale for 0'
FROM cte_Rn a
)
SELECT
Facility_no,
Purchase_Date,
Seller_id,
Sale_id,
-- [Skipped Sale],
[Skipped Sale for 0]
FROM cte_Rn_0 a
WHERE NOT EXISTS
(
select * from cte_Rn_0 b
where b.Sale_id = a.[Skipped Sale for 0]
and a.Facility_no = b.Facility_no
and a.Purchase_Date = b.Purchase_Date
and a.Seller_id = b.Seller_id
)
--ORDER BY Purchase_Date ASC

Converting table data to pie-chart data

Need to plot data extracted for table into a pie-chart.
I am selecting data from a table to count tickets with different scenarios. I am able to simply select data to be plotted in excel.
But I need to select the same data in such a way that It can be plotted in pie-chart also.
SELECT Sum(CASE
WHEN Date(reportdate) < Date(current timestamp)
AND ( status NOT IN (SELECT value
FROM synonymdomain
WHERE maxvalue IN ( 'RESOLVED', 'CLOSED'
,
'REJECTED' )
AND domainid IN ( 'INCIDENTSTATUS'
)) )
AND incident.ir IS NOT NULL THEN 1
end) AS IMs_Balance_Carry_Forward,
( Sum(CASE
WHEN Date(reportdate) = Date(current timestamp)
AND ( status NOT IN (SELECT value
FROM synonymdomain
WHERE maxvalue IN (
'RESOLVED', 'CLOSED',
'REJECTED' )
AND domainid IN (
'INCIDENTSTATUS' )) )
AND ( incident.ir IS NOT NULL ) THEN 1
end) ) AS IM_Added_During_the_day,
from INCIDENT
Current Result:
IMS_BALANCE_CARRY_FORWARD IM_ADDED_DURING_THE_DAY
120 8
Required Result"
Column1 Column2
IMS_BALANCE_CARRY_FORWARD 120
IM_ADDED_DURING_THE_DAY 8
You want an unpivot capability, this has been answered here before. previous question and answer

tsql selecting record based upon date and null

I have a table:
ID as int, ParentId as int, FreeFromTerxt as varchar(max), ActiveUntil as DateTime
As an example, within this table I have two records.
1, 100, 'Some text', '2015-11-30 12:10:09.0000000'
2, 100, 'New text', null
What I am trying to do is get the current active record, which in the case above would by record 1. To do that I just select with the following criteria:
ActiveUntil > GETDATE()
This works great, but if I change the first date to 2015-10-30, I need to get the null record as this record will take precedence.
So I changed the code to be:
((ActiveUntil is NULL) OR (ActiveUntil > GETDATE()))
But this does not work.
Here is some example with union:
DECLARE #t TABLE ( d DATETIME )
INSERT INTO #t
VALUES ( NULL ),
( '2015-11-30' )
SELECT TOP 1 *
FROM ( SELECT * , 1 AS ordering
FROM #t
WHERE d > GETDATE()
UNION ALL
SELECT * , 2 AS ordering
FROM #t
WHERE d IS NULL
) t
ORDER BY ordering, d
For 2015-11-30 it returns 2015-11-30. For 2015-10-30 it returns null.
Try like this:
((ActiveUntil is NULL) OR (CONVERT(char(10), ActiveUntil ,126)) > GETDATE())
Refer MSDN for Cast and Convert. The format specifier 126 is for YYYY-MM-DD. Or you can use CAST
((ActiveUntil is NULL) OR (CAST(ActiveUntil as Date) > GETDATE())

Two questions about my SQL script. How to add subtotal/total lines, and a sorting issue

I have some T-SQL that generates a nice report giving a summary some stuff by month.
I have 2 questions, is there a way to get the to sort the months by calendar order, not by alpha? And, what i would like to do is add a total line for each year, and a total line for the whole report?
SELECT
CASE WHEN tmpActivity.Year IS NULL THEN
CASE WHEN tmpCreated.Year IS NULL THEN
CASE WHEN tmpContactsCreated.Year IS NULL THEN
null
ELSE tmpContactsCreated.Year END
ELSE tmpCreated.Year END
ELSE tmpActivity.Year END As Year,
CASE WHEN tmpActivity.Month IS NULL THEN
CASE WHEN tmpCreated.Month IS NULL THEN
CASE WHEN tmpContactsCreated.Month IS NULL THEN
null
ELSE DateName(month, DateAdd(month, tmpContactsCreated.Month - 1, '1900-01-01' )) END
ELSE DateName(month, DateAdd(month, tmpCreated.Month - 1, '1900-01-01' )) END
ELSE DateName(month, DateAdd(month, tmpActivity.Month - 1, '1900-01-01' )) END As Month,
CASE WHEN tmpActivity.ActiveAccounts IS NULL THEN 0 ELSE tmpActivity.ActiveAccounts END AS ActiveAccounts,
CASE WHEN tmpCreated.NewAccounts IS NULL THEN 0 ELSE tmpCreated.NewAccounts END AS NewAccounts,
CASE WHEN tmpContactsCreated.NewContacts IS NULL THEN 0 ELSE tmpContactsCreated.NewContacts END AS NewContacts
FROM
(
SELECT YEAR(LastLogon) As Year, MONTH(LastLogon) As Month, COUNT(*) As ActiveAccounts
FROM Users
WHERE LastLogon >= '1/1/1800'
GROUP BY YEAR(LastLogon), MONTH(LastLogon)
) as tmpActivity
FULL JOIN
(
SELECT YEAR(Created) As Year, MONTH(Created) As Month, COUNT(*) As NewAccounts
FROM Users
WHERE Created >= '1/1/1800'
GROUP BY YEAR(Created), MONTH(Created)
) as tmpCreated ON tmpCreated.Year = tmpActivity.Year AND tmpCreated.Month = tmpActivity.Month
FULL JOIN
(
SELECT YEAR(Created) As Year, MONTH(Created) As Month, COUNT(*) As NewContacts
FROM Contacts
WHERE Created >= '1/1/1800'
GROUP BY YEAR(Created), MONTH(Created)
) as tmpContactsCreated ON tmpContactsCreated.Year = tmpCreated.Year AND tmpContactsCreated.Month = tmpCreated.Month
Order By Year DESC, Month DESC
To order by the month use the following:
ORDER BY DATEPART(Month,Created) ASC
DatePart() returns an integer for the part specified 1 for January, 2 for Febuary etc.
You're SQL could be helped with the COALESCE() and ISNULL() functions. This is the same as your first select:
SELECT
COALESCE(tmpActivity.Year,tmpCreated.Year,tmpContactsCreated.Year) as Year,
COALESCE(tmpActivity.Month,tmpCreated.Month,tmpContactsCreated.Month) as Month,
ISNULL(tmpActivity.ActiveAccounts,0) AS ActiveAccounts,
ISNULL(tmpCreated.NewAccounts,0) AS NewAccounts,
ISNULL(tmpContactsCreated.NewContacts,0) AS NewContacts
I think there is a bug in your select, I believe your last line has to be this:
) as tmpContactsCreated ON (tmpContactsCreated.Year = tmpCreated.Year AND tmpContactsCreated.Month = tmpCreated.Month) OR
(tmpContactsCreated.Year = tmpActivity.Year AND tmpContactsCreated.Month = tmpActivity.Month)
But I would have to test this to be sure.
Adding in rollups is hard to do -- typically this is done externally to the SQL in the control or whatever displays the results. You could do something like this (contrived example):
SELECT 1 as reportOrder, date, amount, null as total
FROM invoices
UNION ALL
SELECT 2 , null, null, sum(amount)
FROM invoices
ORDER BY reportOrder, date
or you could not have the "extra" total column and put it in the amount column.