Lisp Pretty Print Object on One Line - lisp

I'm writing a list of lists to a .dot file to generate a tree. It seems that the pretty printer in lisp inserts new lines in the output so when I execute the dot file, the new lines make it hard to read the generated graph.
I've looked at the format documentation, but I haven't quite been able to make good use of it.
Here is a sample list that should be printed:
(((TOWER 'D 'C ^LEFT '0 ^RIGHT '2 ^BOTTOM '4 ^TOP '8)
(TOWER 'C 'B ^LEFT '0 ^RIGHT '2 ^BOTTOM '2 ^TOP '6)
(TOWER 'B 'A ^LEFT '0 ^RIGHT '2 ^BOTTOM '0 ^TOP '4) (ON 'D 'C)
(ON 'C 'B) (ON 'B 'A))
((TOWER 'D 'C ^LEFT '0 ^RIGHT '2 ^BOTTOM '4 ^TOP '8)
(TOWER 'C 'B ^LEFT '0 ^RIGHT '2 ^BOTTOM '2 ^TOP '6)
(TOWER 'B 'A ^LEFT '0 ^RIGHT '2 ^BOTTOM '0 ^TOP '4) (ON 'D 'C)
(ON 'C 'B) (ON 'B 'A))
((TOWER 'D 'C ^LEFT '0 ^RIGHT '2 ^BOTTOM '4 ^TOP '8)
(TOWER 'C 'B ^LEFT '0 ^RIGHT '2 ^BOTTOM '2 ^TOP '6)
(TOWER 'B 'A ^LEFT '0 ^RIGHT '2 ^BOTTOM '0 ^TOP '4) (ON 'D 'C)
(ON 'C 'B) (ON 'B 'A))
((TOWER 'D 'C ^LEFT '0 ^RIGHT '2 ^BOTTOM '4 ^TOP '8)
(TOWER 'C 'B ^LEFT '0 ^RIGHT '2 ^BOTTOM '2 ^TOP '6)
(TOWER 'B 'A ^LEFT '0 ^RIGHT '2 ^BOTTOM '0 ^TOP '4) (ON 'D 'C)
(ON 'C 'B) (ON 'B 'A))
((TOWER 'D 'C ^LEFT '0 ^RIGHT '2 ^BOTTOM '4 ^TOP '8)
(TOWER 'C 'B ^LEFT '0 ^RIGHT '2 ^BOTTOM '2 ^TOP '6)
(TOWER 'B 'A ^LEFT '0 ^RIGHT '2 ^BOTTOM '0 ^TOP '4) (ON 'D 'C)
(ON 'C 'B) (ON 'B 'A))
((TOWER 'D 'C ^LEFT '0 ^RIGHT '2 ^BOTTOM '4 ^TOP '8)
(TOWER 'C 'B ^LEFT '0 ^RIGHT '2 ^BOTTOM '2 ^TOP '6)
(TOWER 'B 'A ^LEFT '0 ^RIGHT '2 ^BOTTOM '0 ^TOP '4) (ON 'D 'C)
(ON 'C 'B) (ON 'B 'A)))
Here is how the list gets printed to the file:
(((TOWER 'D 'C
^LEFT '0
^RIGHT '2
^BOTTOM '4
^TOP '8)
(TOWER 'C 'B
^LEFT '0
^RIGHT '2
^BOTTOM '2
^TOP '6)
(TOWER 'B 'A
^LEFT '0
^RIGHT '2
^BOTTOM '0
^TOP '4)
(ON 'D 'C)
(ON 'C 'B)
(ON 'B 'A))
((TOWER 'D 'C
^LEFT '0
^RIGHT '2
^BOTTOM '4
^TOP '8)
(TOWER 'C 'B
^LEFT '0
^RIGHT '2
^BOTTOM '2
^TOP '6)
(TOWER 'B 'A
^LEFT '0
^RIGHT '2
^BOTTOM '0
^TOP '4)
(ON 'D 'C)
(ON 'C 'B)
(ON 'B 'A))
((TOWER 'D 'C
^LEFT '0
^RIGHT '2
^BOTTOM '4
^TOP '8)
(TOWER 'C 'B
^LEFT '0
^RIGHT '2
^BOTTOM '2
^TOP '6)
(TOWER 'B 'A
^LEFT '0
^RIGHT '2
^BOTTOM '0
...
...
...
What format directives should use to get the properly formatted output?
Here is the code I'm using
(format stream "~A [shape=record, label=\"{~A|~A|~A}\"];~%" a b c d)

If you set *print-right-margin* to a very large number, the pretty printer should not insert any newlines.
It defaults to nil to mean the width of the device (e.g., your monitor).

Related

invalid reference to FROM-clause entry with CTE

I'm trying to write a query to generate time periods but am getting the error:
ERROR: invalid reference to FROM-clause entry for table "prop"
Hint: There is an entry for table "prop", but it cannot be referenced from this part of the query.
Position: 346
The query is:
WITH prop AS (SELECT p.stagger, p.tariff FROM core_property p WHERE p.id = 1)
SELECT day + (hour.a * INTERVAL '1 hour') AS time,
day + (hour.b * INTERVAL '1 hour') AS timeEnd
FROM prop,
GENERATE_SERIES(date '2022-05-18' + prop.stagger, date '2022-05-20', '1 day'::INTERVAL) day,
(SELECT UNNEST(CASE
WHEN prop.tariff = 'Economy 7' THEN ARRAY [0,12,18]
WHEN prop.tariff = 'Economy 10' THEN ARRAY [0] END) a,
UNNEST(CASE
WHEN prop.tariff = 'Economy 7' THEN ARRAY [5,13,20]
WHEN prop.tariff = 'Economy 10' THEN ARRAY [7] END) b) hour;
I have a version of this query that almost works but generates duplicates and is ugly:
SELECT day + p.stagger + (CASE
WHEN p.tariff = 'Economy 7' THEN e7.a
WHEN p.tariff = 'Economy 10' THEN e10.a END) * INTERVAL '1 hour' AS time,
day + p.stagger + (CASE
WHEN p.tariff = 'Economy 7' THEN e7.b
WHEN p.tariff = 'Economy 10' THEN e10.b END) * INTERVAL '1 hour' AS timeEnd
FROM GENERATE_SERIES(date '2022-05-18', date '2022-05-20', '1 day'::INTERVAL) day,
(SELECT UNNEST(ARRAY [0,13,20]) a, UNNEST(ARRAY [5,16,22]) b) e10,
(SELECT UNNEST(ARRAY [0]) a, UNNEST(ARRAY [7]) b) e7,
(SELECT p.stagger, p.tariff FROM core_property p WHERE p.id = 1) p;
The result is this when p.tariff = 'Economy 7', but there should only be one entry for each day:
+---------------------------------+---------------------------------+
|time |timeend |
+---------------------------------+---------------------------------+
|2022-05-18 00:15:00.000000 +00:00|2022-05-18 07:15:00.000000 +00:00|
|2022-05-18 00:15:00.000000 +00:00|2022-05-18 07:15:00.000000 +00:00|
|2022-05-18 00:15:00.000000 +00:00|2022-05-18 07:15:00.000000 +00:00|
|2022-05-19 00:15:00.000000 +00:00|2022-05-19 07:15:00.000000 +00:00|
|2022-05-19 00:15:00.000000 +00:00|2022-05-19 07:15:00.000000 +00:00|
|2022-05-19 00:15:00.000000 +00:00|2022-05-19 07:15:00.000000 +00:00|
|2022-05-20 00:15:00.000000 +00:00|2022-05-20 07:15:00.000000 +00:00|
|2022-05-20 00:15:00.000000 +00:00|2022-05-20 07:15:00.000000 +00:00|
|2022-05-20 00:15:00.000000 +00:00|2022-05-20 07:15:00.000000 +00:00|
+---------------------------------+---------------------------------+
When p.tariff = 'Economy 10' then the result is right:
+---------------------------------+---------------------------------+
|time |timeend |
+---------------------------------+---------------------------------+
|2022-05-18 00:15:00.000000 +00:00|2022-05-18 05:15:00.000000 +00:00|
|2022-05-18 13:15:00.000000 +00:00|2022-05-18 16:15:00.000000 +00:00|
|2022-05-18 20:15:00.000000 +00:00|2022-05-18 22:15:00.000000 +00:00|
|2022-05-19 00:15:00.000000 +00:00|2022-05-19 05:15:00.000000 +00:00|
|2022-05-19 13:15:00.000000 +00:00|2022-05-19 16:15:00.000000 +00:00|
|2022-05-19 20:15:00.000000 +00:00|2022-05-19 22:15:00.000000 +00:00|
|2022-05-20 00:15:00.000000 +00:00|2022-05-20 05:15:00.000000 +00:00|
|2022-05-20 13:15:00.000000 +00:00|2022-05-20 16:15:00.000000 +00:00|
|2022-05-20 20:15:00.000000 +00:00|2022-05-20 22:15:00.000000 +00:00|
+---------------------------------+---------------------------------+
I'm not sure if I really need a CTE but it seemed like the only way to use prop.tariff and prop.stagger in the FROM clause.
A subquery in a FROM/JOIN list cannot reference other tables of the FROM/JOIN list, unless the join is declared as lateral. So declare it as LATERAL.
WITH prop AS (SELECT p.stagger, p.tariff FROM core_property p WHERE p.id = 1)
SELECT day + (hour.a * INTERVAL '1 hour') AS time,
day + (hour.b * INTERVAL '1 hour') AS timeEnd
FROM prop,
GENERATE_SERIES(date '2022-05-18' + prop.stagger, date '2022-05-20', '1 day'::INTERVAL) day,
LATERAL (SELECT UNNEST(CASE
WHEN prop.tariff = 'Economy 7' THEN ARRAY [0,12,18]
WHEN prop.tariff = 'Economy 10' THEN ARRAY [0] END) a,
UNNEST(CASE
WHEN prop.tariff = 'Economy 7' THEN ARRAY [5,13,20]
WHEN prop.tariff = 'Economy 10' THEN ARRAY [7] END) b) hour;
An exception to this is a bare set-returning function used in the FROM/JOIN list, which is implicitly treated as lateral. Which is why the `generate_series(...) doesn't throw the same error.

sql pivot month result to year format

How can I get the year column information,
which is not clear like the month, in the header?
select
isnull (group_info, 'grand total') as 'group_definition',
isnull (sum (case datepart(month, shipment_date) when 1 then amount end),0) as 1,
isnull (sum (case datepart(month, shipment_date) when 2 then amount end),0) as 2,
isnull (sum (case datepart(month, shipment_date) when 3 then amount end),0) as 3,
isnull (sum (case datepart(month, shipment_date) when 4 then amount end),0) as 4,
isnull (sum (case datepart(month, shipment_date) when 5 then amount end),0) as 5,
isnull (sum (case datepart(month, shipment_date) when 6 then amount end),0) as 6,
isnull (sum (case datepart(month, shipment_date) when 7 then amount end),0) as 7,
isnull (sum (case datepart(month, shipment_date) when 8 then amount end),0) as 8,
isnull (sum (case datepart(month, shipment_date) when 9 then amount end),0) as 9,
isnull (sum (case datepart(month, shipment_date) when 10 then amount end),0) as 10,
isnull (sum (case datepart(month, shipment_date) when 11 then amount end),0) as 11,
isnull (sum (case datepart(month, shipment_date) when 12 then amount end),0) as 12,
isnull (sum (amount),0) as grandtotal
from invoice
group by groupıng sets
((datepart(year, shipment_date), group_info), ());

Calculate Fiscal Year

I am generating a case statement that will be a master shared dataset for our report date ranges since we frequently use the same date ranges. Currently I have previous week, previous month, previous year, current week, current month and current year. I would like to add our fiscal year which is (10/1 to 9/30) as well but I haven't been able to come up with a pure SQL way to do it.
DECLARE #frequency as nvarchar(20);
SET #frequency = 'CURRENT MONTH'
SELECT
CASE #frequency
WHEN 'PREVIOUS MONTH' THEN CONVERT(DATE,DATEADD(m,DATEDIFF(m,0,GETDATE())-1,0))
WHEN 'CURRENT MONTH' THEN CONVERT(DATE,DATEADD(dd, 0, DATEDIFF(dd, 0, DATEADD(dd,-(DAY(GETDATE())-1),GETDATE()))))
WHEN 'CURRENT WEEK' THEN CONVERT(DATE,DATEADD(dd, 1, DATEDIFF(dd, 0,DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), CAST(GETDATE() AS DATETIME)))))
WHEN 'PREVIOUS WEEK' THEN CONVERT(DATE,DATEADD(dd, -6, DATEDIFF(dd, 0,DATEADD(DAY, 1 - DATEPART(WEEKDAY, GETDATE()), CAST(GETDATE() AS DATETIME)))))
WHEN 'CURRENT YEAR' THEN CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0))
WHEN 'PREVIOUS YEAR' THEN CONVERT(DATE, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()) - 1, 0))
END as [START DATE],
CASE #frequency
WHEN 'PREVIOUS MONTH' THEN CONVERT(DATE,DATEADD(dd, 0, DATEDIFF(dd, 0,DATEADD(ms,-2,DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)))))
WHEN 'CURRENT MONTH' THEN CONVERT(DATE,DATEADD(D, -1, DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()) + 1, '19000101')))
WHEN 'CURRENT WEEK' THEN CONVERT(DATE,DATEADD(dd, 1, DATEDIFF(dd, 0,DATEADD(DAY, 7 - DATEPART(WEEKDAY, GETDATE()), CAST(GETDATE() AS DATETIME)))))
WHEN 'PREVIOUS WEEK' THEN CONVERT(DATE,DATEADD(dd, -6, DATEDIFF(dd, 0,DATEADD(DAY, 7 - DATEPART(WEEKDAY, GETDATE()), CAST(GETDATE() AS DATETIME)))))
WHEN 'CURRENT YEAR' THEN CONVERT(DATE, DATEADD(ms, -2, DATEADD(YEAR, 0, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()) + 1, 0))))
WHEN 'PREVIOUS YEAR' THEN CONVERT(DATE, DATEADD(ms, -2, DATEADD(YEAR, 0, DATEADD(YEAR, DATEDIFF(YEAR, 0, GETDATE()), 0))))
END as [END DATE]
I've found the simplest way to perform this logic is to shift your date by the offset. If 10/1/2018 belongs to FY 2018, subtract the 9 months to convert the date to 1/1/2018. Then get the year value.
YEAR(DATEADD(MONTH,-9,'2018-09-01')) = 2017
YEAR(DATEADD(MONTH,-9,'2019-09-01')) = 2018
YEAR(DATEADD(MONTH,-9,[YourDateField]))
With this, you can also calculate the Fiscal Month
MONTH(DATEADD( month, -9, '2018-09-01 )) = 12
My company use the Year the FY ends, so 10/1/2018 would be part of the FY closing 2019. For my arrangement, I would need to add 3 months instead of subtract to get the calculation to come out right.
This approach leverages date math exclusively so should be able to use an index in most situations.
To find the given day for the datepart you're looking for, try this:
SELECT CurrentWeek = DATEADD( WEEK, DATEDIFF( WEEK, '2018-01-01', GETDATE()), '2018-01-01' ),
CurrentMonth = DATEADD( MONTH, DATEDIFF( MONTH, '2018-01-01', GETDATE()), '2018-01-01' ),
CurrentYear = DATEADD( YEAR, DATEDIFF( YEAR, '2018-01-01', GETDATE()), '2018-01-01' )
;
By basing the calculation on a seed date, you don't need to truncate the smaller time values.
According to your calculations, this will work:
DECLARE #frequency as nvarchar(20);
SET #frequency = 'FINANCIAL YEAR'
SELECT
CASE #frequency
WHEN 'FINANCIAL YEAR' THEN CONVERT(date, DATEADD(month, -1,
DATEADD(year, -1, DATEADD(month, -8, DATEADD(month, 13-MONTH(GETDATE()),
DATEDIFF(month, 0, GETDATE()), 0))))))
END as [START DATE],
CASE #frequency
WHEN 'FINANCIAL YEAR' THEN CONVERT(date, DATEADD(ms, -2,
DATEADD(month, -8, DATEADD(month, 13-MONTH(GETDATE()), DATEADD(month,
DATEDIFF(month, 0, GETDATE()), 0)))))
END as [END DATE];
Play with the -8 in order to change the financial year - e.g. if the finacial year if from 2017-03 to 2018-03, then it will be -9.
I hope that's helpful!
P.S. I used April (from 2017-04 to 2018-04) as financial year

How do I code to find 3 or more occurrences within a time period (6 weeks)?

I need to build a patient population based on clinic visits. The qualifying criteria (filter) for this population is 3 visits in a 6 week period over the evaluation year. How can I code this?
DECLARE #Records TABLE (ptID INT, date DATE)
INSERT INTO #Records VALUES
(1, '2016-01-01')
,(1, '2016-01-05')
,(1, '2016-02-01')
,(1, '2016-10-01')
,(2, '2015-12-01')
,(2, '2015-12-10')
,(2, '2015-12-31')
,(2, '2016-01-01')
,(2, '2016-01-05')
,(2, '2016-03-05')
,(3, '2016-01-01')
,(3, '2016-02-01')
,(3, '2016-03-01')
,(3, '2016-04-01')
,(3, '2016-05-01')
,(3, '2016-06-01')
,(3, '2016-07-01')
,(3, '2016-08-01')
select a.ptID , a.date
from #Records a
join #Records b
on a.ptID = b.ptID
and datediff(wk, a.date, b.date) <= 6
and datediff(wk, a.date, b.date) > 0
and DATEPART(yy, a.date) = DATEPART(yy, b.date)
group by a.ptID, a.date
having count(*) >= 2
Paparazzi deserves all the credit for comparing the table to itself. I'm just refining his comparison here.
DECLARE #Records TABLE (
PatientID INT
,VisitDate DATE
)
INSERT INTO #Records VALUES
(1, '2016-01-01')
,(1, '2016-01-05')
,(1, '2016-02-01')
,(1, '2016-10-01')
,(2, '2015-12-01')
,(2, '2016-01-01')
,(2, '2016-01-05')
,(2, '2016-03-05')
;WITH SixWeeks
AS (
SELECT a.PatientID AS PID1, a.VisitDate AS Date1,
b.PatientID AS PID2, b.VisitDate AS Date2,
DATEDIFF(dd, a.VisitDate, b.VisitDate) AS DD
FROM #Records a
JOIN #Records b
ON a.PatientID = b.PatientID
AND DATEDIFF(dd, a.VisitDate, b.VisitDate) <= 42
AND DATEPART(yy,a.VisitDate) = '2016'
WHERE EXISTS (SELECT * FROM #Records WHERE (VisitDate > a.VisitDate AND VisitDate < b.VisitDate))
)
SELECT PID1 FROM SixWeeks
GROUP BY PID1

Generate series of quarters in Postgresql

I need to generate series of quarters, given start date and end date. I know of generate_series(), but it just does not work with quarter:
SELECT * FROM generate_series('2008-01-01 00:00'::timestamp,'2009-01-01 12:00', '1 quarter');
What makes quarter so special? Otherwise generate_series() works with pretty much everything, from microseconds to millenium:
select * from generate_series('2008-01-01 00:00'::timestamp,'2008-01-01 00:00:00.001', '1 microsecond');
select * from generate_series('2008-01-01 00:00'::timestamp,'2008-01-01 00:01', '1 second');
select * from generate_series('2008-01-01 00:00'::timestamp,'2008-01-01 01:00', '1 minute');
select * from generate_series('2008-01-01 00:00'::timestamp,'2008-01-01 12:00', '1 hour');
select * from generate_series('2008-01-01 00:00'::timestamp,'2009-01-01 12:00', '1 day');
select * from generate_series('2008-01-01 00:00'::timestamp,'2009-01-01 12:00', '1 week');
select * from generate_series('2008-01-01 00:00'::timestamp,'2009-01-01 12:00', '1 month');
select * from generate_series('2008-01-01 00:00'::timestamp,'2009-01-01 12:00', '1 year');
select * from generate_series('2008-01-01 00:00'::timestamp,'2009-01-01 12:00', '1 decade');
select * from generate_series('2008-01-01 00:00'::timestamp,'2009-01-01 12:00', '1 century');
select * from generate_series('2008-01-01 00:00'::timestamp,'2009-01-01 12:00', '1 millennium');
If quarter cannot be used then what is the best other option? For now, I have:
select
date_trunc('quarter',generate_series) gs
from
generate_series('2008-01-01 00:00'::timestamp,'2009-01-01 12:00', '1 month')
group by
gs
order by
gs;
Shouldn't this do what you expect:
SELECT * FROM generate_series('2008-01-01 00:00'::timestamp,
'2009-01-01 12:00', '3 months');
Result:
generate_series
---------------------
2008-01-01 00:00:00
2008-04-01 00:00:00
2008-07-01 00:00:00
2008-10-01 00:00:00
2009-01-01 00:00:00
(5 rows)