'MM-yyyy' date/string format for query parameter in SAP crystal report's command - crystal-reports

We are working on an MM-yyyy parameter, it goes like this
Crystal Report's "Command" (STRING PARAMETER NAME = P_DATE_From and P_DATE_TO)
Select Column1,
Column2
from [dbo].[saptable] t1
where convert(date, t1.[DateColumn]) between convert(date,CONCAT(SUBSTRING({?P_DATE_From}, 4, 7),'-',SUBSTRING({?P_DATE_From}, 1, 2),'-', '01'))
and
EOMONTH(cast(CONCAT(SUBSTRING({?P_DATE_TO}, 1, 2), '-', '01', '-', SUBSTRING({?P_DATE_TO}, 4, 7)) as date))
but no data can be retrieved from the said query in SAP command.
I was able to successfully execute the idea through "RECORDS FORMULA" in SAP Crystal reports.
but the report will become less efficient as time goes due to the number of data contained in the table.

Related

How to format date in SSRS?

In SSRS report query is generating date as a column in the format of :
Sales ID20200331 ID20200430 ID20200531
To remove the ID i used following expression:
=Right( Fields!ID20210331.Value, len(Fields!ID20210331.Value) - 2)
This gives me 84, instead of removing ID.
How can I remove ID and format date as 2020 Mar etc.
Thanks
If your fields values are "ID20200430" etc then in SSRS you can use something like this..
=DateSerial(
MID(Fields!IDDate.Value, 3, 4),
MID(Fields!IDDate.Value, 7, 2),
RIGHT(Fields!IDDate.Value, 2)
)
However It appears that it's your column [names] that represent dates is this correct?
If this is true, then you would have to UNPIVOT the columns in SQL then convert the resulting values into a real date format.
Here' some sample data to show how to do this.
DECLARE #t TABLE (Sales varchar(10), ID20200331 int, ID20200430 int, ID20200531 int)
INSERT INTO #t VALUES
('A', 1,2,3),
('B', 4,5,6),
('C', 7,8,9)
SELECT
Sales, IdDate, SomeNumber
, MyDate = DATEFROMPARTS(SUBSTRING(IdDate, 3, 4), SUBSTRING(IdDate, 7, 2), SUBSTRING(IdDate, 9, 2))
FROM #t
UNPIVOT(
SomeNumber FOR IdDate IN ([ID20200331],[ID20200430],[ID20200531])
) unpvt
Which gives us this including the myDate column which is the correct date type
You could then use this in a matrix control in SSRS to get the data back into a pivoted view

Make rows to Columns in Postgresql [duplicate]

Does any one know how to create crosstab queries in PostgreSQL?
For example I have the following table:
Section Status Count
A Active 1
A Inactive 2
B Active 4
B Inactive 5
I would like the query to return the following crosstab:
Section Active Inactive
A 1 2
B 4 5
Is this possible?
Install the additional module tablefunc once per database, which provides the function crosstab(). Since Postgres 9.1 you can use CREATE EXTENSION for that:
CREATE EXTENSION IF NOT EXISTS tablefunc;
Improved test case
CREATE TABLE tbl (
section text
, status text
, ct integer -- "count" is a reserved word in standard SQL
);
INSERT INTO tbl VALUES
('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
, ('C', 'Inactive', 7); -- ('C', 'Active') is missing
Simple form - not fit for missing attributes
crosstab(text) with 1 input parameter:
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- needs to be "ORDER BY 1,2" here
) AS ct ("Section" text, "Active" int, "Inactive" int);
Returns:
Section | Active | Inactive
---------+--------+----------
A | 1 | 2
B | 4 | 5
C | 7 | -- !!
No need for casting and renaming.
Note the incorrect result for C: the value 7 is filled in for the first column. Sometimes, this behavior is desirable, but not for this use case.
The simple form is also limited to exactly three columns in the provided input query: row_name, category, value. There is no room for extra columns like in the 2-parameter alternative below.
Safe form
crosstab(text, text) with 2 input parameters:
SELECT *
FROM crosstab(
'SELECT section, status, ct
FROM tbl
ORDER BY 1,2' -- could also just be "ORDER BY 1" here
, $$VALUES ('Active'::text), ('Inactive')$$
) AS ct ("Section" text, "Active" int, "Inactive" int);
Returns:
Section | Active | Inactive
---------+--------+----------
A | 1 | 2
B | 4 | 5
C | | 7 -- !!
Note the correct result for C.
The second parameter can be any query that returns one row per attribute matching the order of the column definition at the end. Often you will want to query distinct attributes from the underlying table like this:
'SELECT DISTINCT attribute FROM tbl ORDER BY 1'
That's in the manual.
Since you have to spell out all columns in a column definition list anyway (except for pre-defined crosstabN() variants), it is typically more efficient to provide a short list in a VALUES expression like demonstrated:
$$VALUES ('Active'::text), ('Inactive')$$)
Or (not in the manual):
$$SELECT unnest('{Active,Inactive}'::text[])$$ -- short syntax for long lists
I used dollar quoting to make quoting easier.
You can even output columns with different data types with crosstab(text, text) - as long as the text representation of the value column is valid input for the target type. This way you might have attributes of different kind and output text, date, numeric etc. for respective attributes. There is a code example at the end of the chapter crosstab(text, text) in the manual.
db<>fiddle here
Effect of excess input rows
Excess input rows are handled differently - duplicate rows for the same ("row_name", "category") combination - (section, status) in the above example.
The 1-parameter form fills in available value columns from left to right. Excess values are discarded.
Earlier input rows win.
The 2-parameter form assigns each input value to its dedicated column, overwriting any previous assignment.
Later input rows win.
Typically, you don't have duplicates to begin with. But if you do, carefully adjust the sort order to your requirements - and document what's happening.
Or get fast arbitrary results if you don't care. Just be aware of the effect.
Advanced examples
Pivot on Multiple Columns using Tablefunc - also demonstrating mentioned "extra columns"
Dynamic alternative to pivot with CASE and GROUP BY
\crosstabview in psql
Postgres 9.6 added this meta-command to its default interactive terminal psql. You can run the query you would use as first crosstab() parameter and feed it to \crosstabview (immediately or in the next step). Like:
db=> SELECT section, status, ct FROM tbl \crosstabview
Similar result as above, but it's a representation feature on the client side exclusively. Input rows are treated slightly differently, hence ORDER BY is not required. Details for \crosstabview in the manual. There are more code examples at the bottom of that page.
Related answer on dba.SE by Daniel Vérité (the author of the psql feature):
How do I generate a pivoted CROSS JOIN where the resulting table definition is unknown?
SELECT section,
SUM(CASE status WHEN 'Active' THEN count ELSE 0 END) AS active, --here you pivot each status value as a separate column explicitly
SUM(CASE status WHEN 'Inactive' THEN count ELSE 0 END) AS inactive --here you pivot each status value as a separate column explicitly
FROM t
GROUP BY section
You can use the crosstab() function of the additional module tablefunc - which you have to install once per database. Since PostgreSQL 9.1 you can use CREATE EXTENSION for that:
CREATE EXTENSION tablefunc;
In your case, I believe it would look something like this:
CREATE TABLE t (Section CHAR(1), Status VARCHAR(10), Count integer);
INSERT INTO t VALUES ('A', 'Active', 1);
INSERT INTO t VALUES ('A', 'Inactive', 2);
INSERT INTO t VALUES ('B', 'Active', 4);
INSERT INTO t VALUES ('B', 'Inactive', 5);
SELECT row_name AS Section,
category_1::integer AS Active,
category_2::integer AS Inactive
FROM crosstab('select section::text, status, count::text from t',2)
AS ct (row_name text, category_1 text, category_2 text);
DB Fiddle here:
Everything works: https://dbfiddle.uk/iKCW9Uhh
Without CREATE EXTENSION tablefunc; you get this error: https://dbfiddle.uk/j8W1CMvI
ERROR: function crosstab(unknown, integer) does not exist
LINE 4: FROM crosstab('select section::text, status, count::text fro...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Solution with JSON aggregation:
CREATE TEMP TABLE t (
section text
, status text
, ct integer -- don't use "count" as column name.
);
INSERT INTO t VALUES
('A', 'Active', 1), ('A', 'Inactive', 2)
, ('B', 'Active', 4), ('B', 'Inactive', 5)
, ('C', 'Inactive', 7);
SELECT section,
(obj ->> 'Active')::int AS active,
(obj ->> 'Inactive')::int AS inactive
FROM (SELECT section, json_object_agg(status,ct) AS obj
FROM t
GROUP BY section
)X
Sorry this isn't complete because I can't test it here, but it may get you off in the right direction. I'm translating from something I use that makes a similar query:
select mt.section, mt1.count as Active, mt2.count as Inactive
from mytable mt
left join (select section, count from mytable where status='Active')mt1
on mt.section = mt1.section
left join (select section, count from mytable where status='Inactive')mt2
on mt.section = mt2.section
group by mt.section,
mt1.count,
mt2.count
order by mt.section asc;
The code I'm working from is:
select m.typeID, m1.highBid, m2.lowAsk, m1.highBid - m2.lowAsk as diff, 100*(m1.highBid - m2.lowAsk)/m2.lowAsk as diffPercent
from mktTrades m
left join (select typeID,MAX(price) as highBid from mktTrades where bid=1 group by typeID)m1
on m.typeID = m1.typeID
left join (select typeID,MIN(price) as lowAsk from mktTrades where bid=0 group by typeID)m2
on m1.typeID = m2.typeID
group by m.typeID,
m1.highBid,
m2.lowAsk
order by diffPercent desc;
which will return a typeID, the highest price bid and the lowest price asked and the difference between the two (a positive difference would mean something could be bought for less than it can be sold).
There's a different dynamic method that I've devised, one that employs a dynamic rec. type (a temp table, built via an anonymous procedure) & JSON. This may be useful for an end-user who can't install the tablefunc/crosstab extension, but can still create temp tables or run anon. proc's.
The example assumes all the xtab columns are the same type (INTEGER), but the # of columns is data-driven & variadic. That said, JSON aggregate functions do allow for mixed data types, so there's potential for innovation via the use of embedded composite (mixed) types.
The real meat of it can be reduced down to one step if you want to statically define the rec. type inside the JSON recordset function (via nested SELECTs that emit a composite type).
dbfiddle.uk
https://dbfiddle.uk/N1EzugHk
Crosstab function is available under the tablefunc extension. You'll have to create this extension one time for the database.
CREATE EXTENSION tablefunc;
You can use the below code to create pivot table using cross tab:
create table test_Crosstab( section text,
status text,
count numeric)
insert into test_Crosstab values ( 'A','Active',1)
,( 'A','Inactive',2)
,( 'B','Active',4)
,( 'B','Inactive',5)
select * from crosstab(
'select section
,status
,count
from test_crosstab'
)as ctab ("Section" text,"Active" numeric,"Inactive" numeric)

SELECT previous year data based on year column

I am trying to develop a SSRS report. I have taken sales values from a transactional table and grouped them by year, month and subcategory. I have created this as a view. Here is the view code:
SELECT b.FiscalYear AS Year,
b.FiscalMonth AS Month,
a.SubCategoryKey,
MAX(a.SubCategoryDesc) AS SubCategoryDesc,
SUM(CAST(a.Cost + a.FreightCost AS decimal(18, 2))) AS TotalCost,
SUM(CAST(a.SalesAmount AS decimal(18, 2))) AS TotalSales,
SUM(CAST(a.Weight AS decimal(18, 2))) AS Pounds, SUM(CAST(a.SalesAmount -(a.Cost + a.FreightCost) AS decimal(18, 2))) AS Margin
FROM dbo.GrossMargin_CorrectedCosts AS a
LEFT OUTER JOIN dbo.M_DateDim AS b ON a.InvoiceDate = b.Date
GROUP BY b.FiscalYear, b.FiscalMonth, a.SubCategoryKey
I am then left with a clean view that looks like this:
SELECT [Year]
,[Month]
,[SubCategoryKey]
,[SubCategoryDesc]
,[TotalCost]
,[TotalSales]
,[Pounds]
,[Margin]
FROM [FinancialData].[dbo].[SubCategorySalesbyMonth_V]\
I'd now like to add additonal columns to this query. I am going to run this as a SSRS report and pass both Year and Month parameters. What I'd like to do is when 2017 is selected as the passed Year parameters, then I would like to show previous year values for TotalSales, TotalCost and Pounds.
Whereas the query would look something like this:
SELECT [Year]
,[Month]
,[SubCategoryKey]
,[SubCategoryDesc]
,[TotalCost]
,[TotalSales]
,[Pounds]
,[Margin]
,PreviousYearTotalSales
,PreviousYearTotalCost
,PreviousYearPounds
FROM [FinancialData].[dbo].[SubCategorySalesbyMonth_V]
Essentially when a year and month is passed to the report, I'd like to show the previous years totalsales, totalcost and pounds for that given period minus one year. I am having a heck of time doing this.
I feel like I have tried everything but obviously not. Please help.
Something that could work now that you have a view to work with is the following query.
SELECT CY.[Year]
,CY.[Month]
,CY.[SubCategoryKey]
,CY.[SubCategoryDesc]
,CY.[TotalCost]
,CY.[TotalSales]
,CY.[Pounds]
,CY.[Margin]
,PY.[TotalSales] AS PreviousYearTotalSales
,PY.[TotalCost] AS PreviousYearTotalCost
,PY.[Pounds] AS PreviousYearPounds
FROM [FinancialData].[dbo].[SubCategorySalesbyMonth_V] CY LEFT JOIN [FinancialData].[dbo].[SubCategorySalesbyMonth_V] PY
ON CY.[Year] - 1 = PY.[Year]
AND CY.[Month] = PY.[Month]
AND CY.[SubCategoryKey] = PY.[SubCategoryKey]
AND CY.[Month] = PY.[Month]
This is just a simple self left join to the same view, but the year from the current year (CY) is joining back to the prior year (PY), year - 1. It is a LEFT JOIN, so the prior year's values will be null if there isn't any prior year/month's data available.
Hope this helps.

OrientDB - Concatenate two strings and aggregate them

Normally, if I want to concatenate two strings and apply an aggregate I follow this syntax:
Sql Server
SELECT substring(t.field, 1, 3) + substring(t.field, 5,7), count(*)
FROM myTable t
GROUP BY substring(t.field, 1, 3) + substring(t.field, 5,7)
Oracle
SELECT CONCAT(substring(t.field, 1, 3), substring(t.field, 5,7)), count(*)
FROM myTable t
GROUP BY CONCAT(substring(t.field, 1, 3), substring(t.field, 5,7))
In OrientDB, is it possible concatenate two strings and get an aggregate of them?
Try this, the parser and the query executor of OrientDb can be some time a litle choosy expecially with the group by option, this would work with the 'Strict mode' disabled (studio -> log in -> db -> second tab on the bottom)
SELECT id, $goofy , count(*) as cont from myTable
LET $sub = id.subString(4),
$goofy = id.subString(1,3).append($sub)
group by $goofy
note:
i've splitted the code in 2 variable couse the parser have some problem parsing the function inside the .append
I'm pretty sure that in the next releases of Orientdb this kind of issue will be fixed (they alredy have a new parser in development)

Crystal Report - Conditional selection of record

I'm using Crystal Reports XI.
My data is coming from a dataset.
I have 2 tables which are related as follows:
Product(ProdID(PK), ProdName)
ProdPC(ProdPCID(PK), ProdID(FK), PCType, ProdCode)
The 'PCType' field determins the type of barcode format the 'ProdCode' represents. (E.g. EAN13, EAN8).
In crystal reports one 'Product' can have more than one kind of barcode which means my tables end up looking like this:
Product: ("1", "Example Product 1")
ProdPC: ("0", "1", "EAN8", "01234567"), ("1", "1", "EAN13", "012345678910")
In crystal reports I only want to print 1 barcode label for per product. However because they're are 2 records in the 'ProdPC' table, I will get 2 labels being printed for this 1 product.
What I want to do is place a condition in crystal reports which states, "If EAN13 is NULL then display EAN8, ELSE display EAN13"
I do not have access to the dataset and cannot prevent the application which calls Crystal Reports to create the barcode labels from sending more than 1 record for the 'ProdPC' table.
How can I create my conditional statement, purely in 'Crystal Reports 2008'?
What I have tried so far is:
IF {PartPC.PCType} = "EAN-13" AND {PartPC.ProdCode} <> "" THEN
{PartPC.ProdCode}
ELSE
/* DISPLAY PartPC.ProdCode containing EAN8 value */
;
But I am unsure how to then tell Crystal Reports to display the 'ProdCode' value where 'PCType' is equal to 'EAN8'
Group your report by Product ID.
Order your report by PC Type descending (within Product ID).
Include your report details in the Product ID footer (not the details section).
Option I: create two columns: one for each bar code. Do this in Crystal Reports.
Remove the PartPC table, replacing it with two SQL Expression fields:
// {%EAN-8}
(
SELECT ProdCode
FROM PartPC
WHERE ProdID=Product.ProdID
AND PCType='EAN-8'
)
// {%EAN-13}
(
SELECT ProdCode
FROM PartPC
WHERE ProdID=Product.ProdID
AND PCType='EAN-13'
)
Then create a formula field to display the appropriate one:
// {#barcode}
If Not(Isnull({%EAN-13})) Then
{%EAN-13}
Else
{%EAN-8}
Option II: alter the SQL to create to scalar-valued fields. Do this in your dataset or in a Command object (Crystal Reports).
SELECT Product.*,
(
SELECT ProdCode
FROM PartPC
WHERE ProdID=Product.ProdID
AND PCType='EAN-8'
) EAN_8,
(
SELECT ProdCode
FROM PartPC
WHERE ProdID=Product.ProdID
AND PCType='EAN-13'
) EAN_13
FROM Product
...