问题
As I was advised by a good man and programmer I should simplify my table. So far I have made a new table (x-month,y-cities,value-Nettotal) it works, but still I didn't understand why it can't group the values (nettotal) by cities. It's OK with month, but the values just come starting from left to right without any 0 left behind. Anyway I hope you will understand everything from the source:
here are the queries:
<cfquery name="GET_SALES_TOTAL" datasource="#dsn#">
SELECT
SUM(COALESCE(nettotal,0)) nettotal,
SC.CITY_ID,
DATEPART(MM,INVOICE_DATE) AY,
C.FULLNAME,
SC.CITY_NAME
FROM
#DSN2_ALIAS#.INVOICE I,
SETUP_CITY SC,
COMPANY C
WHERE
C.COMPANY_ID=I.COMPANY_ID
AND SC.CITY_ID=C.CITY
AND PURCHASE_SALES=1
GROUP BY
DATEPART(MM,INVOICE_DATE),
SC.CITY_ID,
C.FULLNAME,
SC.CITY_NAME
ORDER BY
AY,CITY_ID
</cfquery>
<cfquery name="GET_SALES_GRAND_TOTAL" datasource="#dsn#">
SELECT SUM(NETTOTAL) NETTOTAL,SC.CITY_ID,SC.CITY_NAME
FROM #DSN2_ALIAS#.INVOICE I,SETUP_CITY SC,COMPANY C
WHERE C.COMPANY_ID=I.COMPANY_ID AND SC.CITY_ID=C.CITY AND PURCHASE_SALES=1
GROUP BY SC.CITY_ID, SC.CITY_NAME
ORDER BY CITY_ID,CITY_NAME
</cfquery>
and here is the table itself:
<table cellpadding="3" cellspacing="1" class="color-border">
<tr class="color-header">
<td></td>
<cfoutput query="GET_SALES_GRAND_TOTAL" group="city_id">
<td>#city_name#</td>
</cfoutput>
</tr>
<cfoutput query="GET_SALES_TOTAL" group="AY"><!--- months first --->
<tr class="color-row"><!--- month-specific stuff goes here --->
<td>#ay#</td>
<cfoutput group="city_id"><!--- city-specific stuff --->
<td>#tlformat(nettotal,2)#<!--- format NETTOTAL however you want here ---></td>
</cfoutput>
</tr>
</cfoutput>
<tr class="color-header">
<td>City Overal</td>
<cfoutput query="GET_SALES_GRAND_TOTAL" group="city_id">
<td>#tlformat(nettotal,2)#<!--- format NETTOTAL here ---></td>
</cfoutput>
</tr>
</table>
Here is the screenshot to make it more clear:

The other stuff except grouping the cities works perfectly!
回答1:
It looks like the problem that you're having is that there is not a record for every combination of month and city. The setup as it is now is fine if every city has sales every month, but we can improve this code so that it handles "missing" entries properly.
Some databases have specific syntax that will help you make a table like this: for example, Access has TRANSFORM
, Oracle and SQL server have CUBE
and ROLLUP
, MySQL has WITH ROLLUP
. However, you still might have to tweak your CF even after adjusting the query, so let's try working with what you have in a more general form.
Instead of an inner join, we want an outer join: all cities plus sales for any city that has sales. However, we also need all months. In this particular instance, we can use a Cartesian product to get months and cities. (Be very careful about these: you should only use them in situations where you really do want one record for every combination of field A and field B. It's easy to use one in the wrong place and get 10,000 records instead of 100.)
Let's take Johan's suggestion and modify it some:
SELECT SUM(COALESCE(NETTOTAL,0)) NETTOTAL
,SC.CITY_ID
,SC.CITY_NAME
,M.INVOICE_MONTH
FROM SETUP_CITY SC
LEFT OUTER JOIN COMPANY C ON SC.CITY_ID = C.CITY
LEFT OUTER JOIN #DSN2_ALIAS#.INVOICE I ON C.COMPANY_ID = I.COMPANY_ID
, (SELECT DISTINCT DATEPART(MM,INVOICE_DATE) INVOICE_MONTH FROM #DSN2_ALIAS#.INVOICE) M
WHERE PURCHASE_SALES = 1
AND DATEPART(MM,I.INVOICE_DATE) = M.INVOICE_MONTH
GROUP BY SC.CITY_ID, SC.CITY_NAME, M.INVOICE_MONTH
ORDER BY SC.CITY_NAME, M.INVOICE_MONTH
I'm a little fuzzy on the format for a Cartesian product with other inner joins present, so give this a try and we can modify it as needed.
That should give you a query with a value for every city for each month with sales. The exact form of the outer join may need to change, depending on the database you're using, but that should at least move you in the right direction.
Note that you will need to change your CF to match the revised query, but just this part, I think:
<cfoutput query="GET_SALES_TOTAL" group="AY"><!--- months first --->
<tr class="color-row"><!--- month-specific stuff goes here --->
<td>#ay#</td>
becomes
<cfoutput query="GET_SALES_TOTAL" group="INVOICE_MONTH"><!--- months first --->
<tr class="color-row"><!--- month-specific stuff goes here --->
<td>#invoice_month#</td>
回答2:
SUM
has the annoying feature of evaluating to null is one of the summed values is null.
Try changing SELECT SUM(NETTOTAL) NETTOTAL
to SELECT SUM(COALESCE(nettotal,0)) nettotal
Remark on query syntax
Please don't use implicit where
joins they are confusing, error prone and bad for your mental health.
Use explicit joins instead:
SELECT SUM(NETTOTAL) NETTOTAL
,SC.CITY_ID
,SC.CITY_NAME
FROM #DSN2_ALIAS#.INVOICE I
INNER JOIN SETUP_CITY SC ON SC.CITY_ID = C.CITY
INNER JOIN COMPANY C ON C.COMPANY_ID = I.COMPANY_ID
WHERE PURCHASE_SALES = 1
GROUP BY SC.CITY_ID, SC.CITY_NAME
ORDER BY SC.CITY_NAME
This way you can separate the join conditions from the filter conditions and your query will be much simpler to maintain and expand if you need to join lots of tables.
And as a bonus you will be unstuck from SQL '89 so you can finally leave the Loveshack.
回答3:
In ColdFusion, when using grouped cfoutput, whichever columns you group on should also be in the ORDER BY part of your query. So change the first query to have ORDER BY AY, city_id
And change the second query to have ORDER BY SC.CITY_NAME, city_id
来源:https://stackoverflow.com/questions/6607421/group-by-cities