I get this error with my query, but I can't figure out what is wrong with it:
Query-specified return tuple has 135 columns but crosstab returns 295.
And here's my query: (The part highlighted in bold returns same number of rows when run separately in pgAdmin.)
SELECT X.*, pi.productcode, pi.productitemdesc, pi.retailsalesprice, cat.productcategorydesc FROM (
SELECT * FROM crosstab (
'SELECT a.productitem AS productitemid, l.locationcode, (CASE WHEN SUM(a.netamount) IS NOT NULL THEN SUM(a.netamount) ELSE 0 END) || ''#'' || (CASE WHEN SUM(a.quantity) IS NOT NULL THEN SUM(a.quantity) ELSE 0 END) AS sales_qty FROM invoiceitem a INNER JOIN invoiceinfo b ON a.invoice = b.invoiceid INNER JOIN locationinfo l ON b.location = l.locationid WHERE b.status !=2 AND l.locationtype = 1 AND l.status = 1 AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')>=''2018-03-01'' AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')<=''2018-03-03'' GROUP BY a.productitem, l.locationcode ORDER BY a.productitem',
'SELECT l.locationcode FROM locationinfo l INNER JOIN invoiceinfo b ON b.location = l.locationid
WHERE b.status !=2 AND l.locationtype = 1 AND l.status = 1 AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')>=''2018-03-01'' AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')<=''2018-03-03'' GROUP BY l.locationcode order by l.locationcode')
AS (productitemid int, "0007" text,"BE101" text,"BE1013" text,"BE1014" text,"BE102" text,"BE103" text,"BE1034" text,"BE104" text,"BE1040" text,"BE1043" text,"BE1044" text,"BE1045" text,"BE1046" text,"BE105" text,"BE106" text,"BE107" text,"BE108" text,"BE109" text,"BE110" text,"BE111" text,"BE112" text,"BE123" text,"BE1265" text,"BE1266" text,"BE1271" text,"BE1272" text,"BE1273" text,"BE1274" text,"BE1279" text,"BE1280" text,"BE1281" text,"BE1282" text,"BE1351" text,"BE1400" text,"BE1401" text,"BE1404" text,"BE141" text,"BE142" text,"BE193" text,"BE194" text,"BE2125" text,"BE2126" text,"BE2127" text,"BE2128" text,"BE3001" text,"BE3002" text,"BE3005" text,"BE3006" text,"BE3009" text,"BE3010" text,"BE3031" text,"BE3032" text,"BE3121" text,"BE3122" text,"BE3123" text,"BE3124" text,"BE3127" text,"BE3128" text,"BE3131" text,"BE3132" text,"BE3203" text,"BE3204" text,"BE325" text,"BE3253" text,"BE3254" text,"BE326" text,"BE332" text,"BE3503" text,"BE3504" text,"BE355" text,"BE356" text,"BE365" text,"BE366" text,"BE381" text,"BE382" text,"BE383" text,"BE384" text,"BE400" text,"BE401" text,"BE402" text,"BE403" text,"BE405" text,"BE406" text,"BE408" text,"BE409" text,"BE411" text,"BE412" text,"BE4311" text,"BE4316" text,"BE4401" text,"BE4402" text,"BE4521" text,"BE4522" text,"BE4551" text,"BE4552" text,"BE470" text,"BE473" text,"BE475" text,"BE481" text,"BE482" text,"BE601" text,"BE604" text,"BE609" text,"BE610" text,"BE7040" text,"BE7043" text,"BE7045" text,"BE7046" text,"BE7048" text,"BE7049" text,"BE708" text,"BE7111" text,"BE7112" text,"BE7127" text,"BE7128" text,"BE7217" text,"BE7218" text,"BE7307" text,"BE7308" text,"BE7351" text,"BE7352" text,"BE801" text,"BE802" text,"BE803" text,"BE804" text,"BE831" text,"BE832" text,"BE860" text,"BE861" text,"BE862" text,"BE863" text,"BE865" text,"BE981" text,"BE982" text
)) X
LEFT JOIN productitem pi ON X.productitemid = pi.productitemid
LEFT JOIN productcategory cat ON pi.productcategory = cat.productcategoryid
The bold part of
productitemid int, "0007" text,"BE101" text,"BE1013" text,"BE1014" text,"BE102" text,"BE103" text,"BE1034" text,"BE104" text,"BE1040" text,"BE1043" text,"BE1044" text,"BE1045" text,"BE1046" text,"BE105" text,"BE106" text,"BE107" text,"BE108" text,"BE109" text,"BE110" text,"BE111" text,"BE112" text,"BE123" text,"BE1265" text,"BE1266" text,"BE1271" text,"BE1272" text,"BE1273" text,"BE1274" text,"BE1279" text,"BE1280" text,"BE1281" text,"BE1282" text,"BE1351" text,"BE1400" text,"BE1401" text,"BE1404" text,"BE141" text,"BE142" text,"BE193" text,"BE194" text,"BE2125" text,"BE2126" text,"BE2127" text,"BE2128" text,"BE3001" text,"BE3002" text,"BE3005" text,"BE3006" text,"BE3009" text,"BE3010" text,"BE3031" text,"BE3032" text,"BE3121" text,"BE3122" text,"BE3123" text,"BE3124" text,"BE3127" text,"BE3128" text,"BE3131" text,"BE3132" text,"BE3203" text,"BE3204" text,"BE325" text,"BE3253" text,"BE3254" text,"BE326" text,"BE332" text,"BE3503" text,"BE3504" text,"BE355" text,"BE356" text,"BE365" text,"BE366" text,"BE381" text,"BE382" text,"BE383" text,"BE384" text,"BE400" text,"BE401" text,"BE402" text,"BE403" text,"BE405" text,"BE406" text,"BE408" text,"BE409" text,"BE411" text,"BE412" text,"BE4311" text,"BE4316" text,"BE4401" text,"BE4402" text,"BE4521" text,"BE4522" text,"BE4551" text,"BE4552" text,"BE470" text,"BE473" text,"BE475" text,"BE481" text,"BE482" text,"BE601" text,"BE604" text,"BE609" text,"BE610" text,"BE7040" text,"BE7043" text,"BE7045" text,"BE7046" text,"BE7048" text,"BE7049" text,"BE708" text,"BE7111" text,"BE7112" text,"BE7127" text,"BE7128" text,"BE7217" text,"BE7218" text,"BE7307" text,"BE7308" text,"BE7351" text,"BE7352" text,"BE801" text,"BE802" text,"BE803" text,"BE804" text,"BE831" text,"BE832" text,"BE860" text,"BE861" text,"BE862" text,"BE863" text,"BE865" text,"BE981" text,"BE982" text
AND
SELECT l.locationcode FROM locationinfo l INNER JOIN invoiceinfo b ON b.location = l.locationid
WHERE b.status !=2 AND l.locationtype = 1 AND l.status = 1 AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')>=''2018-03-01'' AND TO_CHAR (b.invoicedate, ''YYYY-MM-DD'')<=''2018-03-03'' GROUP BY l.locationcode order by l.locationcode
When run seperately, I get 295 results which is correct. However putting it together in the whole query gets the error.
The manual:
The remaining output columns must have the type of the last column of the source_sql query's result, and there must be exactly as many of them as there are rows in the category_sql query's result.
crosstab(text, text) with a dynamic (!) SELECT query as 2nd parameter is very error prone, since the output column list is static. You should also generate the output column list dynamically. Example:
Dynamic alternative to pivot with CASE and GROUP BY
That aside, the different number of rows returned from the same query, may very well be due to a different timezone setting in the two different sessions.
You have the expression TO_CHAR(b.invoicedate, 'YYYY-MM-DD') in your predicates. If b.invoicedate is type timestamptz the result depends on the timezone setting. Consider:
SET timezone = '+10';
SELECT TO_CHAR(timestamptz '2018-04-07 23:30+0', 'YYYY-MM-DD');
to_char
----------
2018-04-08
SET timezone = '-10';
SELECT TO_CHAR(timestamptz '2018-04-07 23:30+0', 'YYYY-MM-DD');
to_char
----------
2018-04-07
Solution
To remove the dependency on the timezone setting, use absolute values.
to_char() is expensive complication in this place to begin with. Drop that and adjust the predicate.
Provide timestamptz values to match your column. This also allows indexes to be used (if applicable).
Return Table Type from A function in PostgreSQL
Use time zone names (not offsets or abbreviations) to avoid more misunderstandings.
Ignoring timezones altogether in Rails and PostgreSQL
Use dollar-quoting to clean up the quote mess.
Insert text with single quotes in PostgreSQL
I suggest this as 2nd parameter:
$$
SELECT l.locationcode
FROM locationinfo l
JOIN invoiceinfo b ON b.location = l.locationid
WHERE b.status <> 2 AND l.locationtype = 1 AND l.status = 1
AND b.invoicedate >= timestamptz '2018-03-01 Europe/Vienna'
AND b.invoicedate < timestamptz '2018-03-04 Europe/Vienna'
GROUP BY 1
ORDER BY 1
$$
Replace Europe/Vienna in my example with the time zone name defining your dates.
Note 2018-03-04 to include all of 2018-03-03 like you intended.
I have Query which need to be modified like if I pass zone=All then it should display all records else other condition. This query I have to use in SSRS Reports, it works in this condition.
select distinct zone, wardno,deptname,
cybertec_view_requests.statusname,
categoryname,opendate,probdesc
from cybertec_view_requests
left join cybertec_view_requests_comments on
cybertec_view_requests_comments.reqid = cybertec_view_requests.id_
where zone= ? and deptname=? and
opendate between ? and ? and categoryname=?
group by zone,wardno,deptname, cybertec_view_requests.statusname,
categoryname,opendate,probdesc
order by zone,wardno,deptname
try this
Hear #zone is your variable to pass in the Query
SELECT DISTINCT zone, wardno,deptname, cybertec_view_requests.statusname, categoryname,opendate,probdesc
FROM cybertec_view_requests
LEFT JOIN cybertec_view_requests_comments ON cybertec_view_requests_comments.reqid = cybertec_view_requests.id_
WHERE zone= CASE WHEN #zone = 'ALL' THEN zone ELSE #zone END and deptname=? and
opendate between ? and ? and categoryname=?
GROUP BY zone,wardno,deptname, cybertec_view_requests.statusname,
categoryname,opendate,probdesc
ORDER BY zone,wardno,deptname
I need a Query to extract the first instance and last instance only between date parameters.
I have a Table recording financial information with financialyearenddate field linked to Company table via companyID. Each company is also linked to programme table and can have multiple programmes. I have a report to pull the financials for each company
on certain programme which I have adjusted to pull only the first and last instance (using MIN & MAX) however I need the first instance.
after a certain date parameter and the last instance before a certain date parameter.
Example: Company ABloggs has financials for 1999,2000,2001,2004,2006,2007,2009 but the programme ran from 2001 to 2007 so I only want
the first financial record and last financial record between those years i.e. 2001 & 2007 records. Any help appreciated.
At the moment I am using 2 queries as I needed the data in a hurry but I need it in 1 query and only where financial year end dates are between parameters and only where there are minimum of 2 GVA records for a company.
Query1:
SELECT
gva.ccx_companyname,
gva.ccx_depreciation,
gva.ccx_exportturnover,
gva.ccx_financialyearenddate,
gva.ccx_netprofitbeforetax,
gva.ccx_totalturnover,
gva.ccx_totalwages,
gva.ccx_statusname,
gva.ccx_status,
gva.ccx_company,
gva.ccx_totalwages + gva.ccx_netprofitbeforetax + gva.ccx_depreciation AS GVA,
gva.ccx_nofulltimeequivalentemployees
FROM
(
SELECT
ccx_companyname,
MAX(ccx_financialyearenddate) AS LatestDate
FROM Filteredccx_gva AS Filteredccx_gva_1
GROUP BY ccx_companyname
) AS min_1
INNER JOIN Filteredccx_gva AS gva
ON min_1.ccx_companyname = gva.ccx_companyname AND
min_1.LatestDate = gva.ccx_financialyearenddate
WHERE (gva.ccx_status = ACTUAL)
Query2:
SELECT
gva.ccx_companyname,
gva.ccx_depreciation,
gva.ccx_exportturnover,
gva.ccx_financialyearenddate,
gva.ccx_netprofitbeforetax,
gva.ccx_totalturnover,
gva.ccx_totalwages,
gva.ccx_statusname,
gva.ccx_status,
gva.ccx_company,
gva.ccx_totalwages + gva.ccx_netprofitbeforetax + gva.ccx_depreciation AS GVA,
gva.ccx_nofulltimeequivalentemployees
FROM
(
SELECT
ccx_companyname,
MIN(ccx_financialyearenddate) AS FirstDate
FROM Filteredccx_gva AS Filteredccx_gva_1
GROUP BY ccx_companyname
) AS MAX_1
INNER JOIN Filteredccx_gva AS gva
ON MAX_1.ccx_companyname = gva.ccx_companyname AND
MAX_1.FirstDate = gva.ccx_financialyearenddate
WHERE (gva.ccx_status = ACTUAL)
Can't you just add a where clause using the first and last date parameters. Something like this:
SELECT <companyId>, MIN(<date>), MAX(<date>)
FROM <table>
WHERE <date> BETWEEN #firstDate AND #lastDate
GROUP BY <companyId>
declare #programme table (ccx_companyname varchar(max), start_year int, end_year int);
insert #programme values
('ABloggs', 2001, 2007);
declare #companies table (ccx_companyname varchar(max), ccx_financialyearenddate int);
insert #companies values
('ABloggs', 1999)
,('ABloggs', 2000)
,('ABloggs', 2001)
,('ABloggs', 2004)
,('ABloggs', 2006)
,('ABloggs', 2007)
,('ABloggs', 2009);
select c.ccx_companyname, min(ccx_financialyearenddate), max(ccx_financialyearenddate)
from #companies c
join #programme p on c.ccx_companyname = p.ccx_companyname
where c.ccx_financialyearenddate >= p.start_year and c.ccx_financialyearenddate <= p.end_year
group by c.ccx_companyname
having count(*) > 1;
You can combine your two original queries into a single query by including the MIN and MAX aggregates in the same GROUP BY query of the virtual table. Also including COUNT() and HAVING COUNT() > 1 ensures company must have at least 2 dates. So query should look like:
SELECT
gva.ccx_companyname,
gva.ccx_depreciation,
gva.ccx_exportturnover,
gva.ccx_financialyearenddate,
gva.ccx_netprofitbeforetax,
gva.ccx_totalturnover,
gva.ccx_totalwages,
gva.ccx_statusname,
gva.ccx_status,
gva.ccx_company,
gva.ccx_totalwages + gva.ccx_netprofitbeforetax + gva.ccx_depreciation AS GVA,
gva.ccx_nofulltimeequivalentemployees
FROM
(SELECT
ccx_companyname,
ccx_status,
MIN(ccx_financialyearenddate) AS FirstDate,
MAX(ccx_financialyearenddate) AS LastDate,
COUNT(*) AS NumDates
FROM Filteredccx_gva AS Filteredccx_gva_1
WHERE (ccx_status = ACTUAL)
GROUP BY ccx_companyname, ccx_status
HAVING COUNT(*) > 1
) AS MinMax
INNER JOIN Filteredccx_gva AS gva
ON MinMax.ccx_companyname = gva.ccx_companyname AND
(MinMax.FirstDate = gva.ccx_financialyearenddate OR
MinMax.LastDate = gva.ccx_financialyearenddate)
WHERE (gva.ccx_status = MinMax.ccx_status)
ORDER BY gva.ccx_companyname, gva.ccx_financialyearenddate
Now this is a simple insert query with one subquery and it's working perfectly:
INSERT INTO CSolutions..Report2
SELECT Nov.Chain, CG.Grouping, reg.code as regcode,reg.pname,reg.fname,reg.sname, SUM(NS.Currency) as sumeur , sum(ns2.kpl) as sumkpl,0,0,0,0
FROM CSolutions..NovSales NS,CSolutions..NSaleskpl NS2, CSolutions..NovCGroup CG, sales..reg_eng reg,
(SELECT DISTINCT P.Code, Nov.Chain
FROM Register..Pcy P
INNER JOIN Register..TCustomer TC ON (P.Code = TC.PCode)
INNER JOIN CSolutions..Novies2 Nov ON (TC.Code = Nov.TCode)
) AS Nov
WHERE NS.SpCode = CG.SpCode and ns.spcode = ns2.spcode AND Ns.PCode = Nov.Code
and ns.spcode = reg.code
and ns.pcode = ns2.pcode
**and NS.SalesMonth = '201205'
and NS2.SalesMonth = '201205'**
GROUP BY Nov.Chain, CG.Grouping , reg.code,reg.pname,reg.fname,reg.sname
This is derivate of the same query, but it's not working correctly:
INSERT INTO CSolutions..Report2
SELECT Nov.Chain, CG.Grouping, reg.code as regcode,reg.pname,reg.fname,reg.sname, SUM(NS.Currency) as sumeur , sum(ns2.kpl) as sumkpl,0,0,0,0
FROM CSolutions..NovSales NS,CSolutions..NSaleskpl NS2, CSolutions..NovCGroup CG, sales..reg_eng reg,
(SELECT DISTINCT P.Code, Nov.Chain
FROM Register..Pcy P
INNER JOIN Register..TCustomer TC ON (P.Code = TC.PCode)
INNER JOIN CSolutions..Novies2 Nov ON (TC.Code = Nov.TCode)
) AS Nov
WHERE NS.SpCode = CG.SpCode and ns.spcode = ns2.spcode AND Ns.PCode = Nov.Code
and ns.spcode = reg.code
and ns.pcode = ns2.pcode
**and NS.SalesMonth between '201201' and '201205'
and NS2.SalesMonth between '201201' and '201205'**
GROUP BY Nov.Chain, CG.Grouping , reg.code,reg.pname,reg.fname,reg.sname
This will give 5 times the 5 month sum amount,
I am a dyslexic and i have hard time to spot the error, I hope someone can help me ?? :)
There is no join on the salesmonth in CSolutions..NovSales and CSolutions..NSaleskpl NS2. In the frist query this does not matter because you are only looking at one salesmonth. In the second query I presume there are multiple salesmonth's as you are selecting a range of value from each table. You are getting a cross join because of this of salesmonth's because of this.