I need to group name in a row - group-by

I have 12 rows for year and name, but I want 1 row for year and name with 12 register in (1 or null).
select id_agente, nombre, ene, feb, mar, abr, may, jun, jul, ago, sep, oct, nov, dic
from (
(select
a.id_agente id_agente,
a.NOMBRE nombre,
case
when to_char (to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '01' then 1 end ene,
case
when to_char (to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '02' then 1 end feb,
..................
)
group by nombre, id_agente, ene, feb, mar, abr, may, jun, jul, ago, sep, oct, nov, dic
order by nombre, id_agente, ene, feb, mar, abr, may, jun, jul, ago, sep, oct, nov, dic;
I hope you help me, thank you very much!

There are several solutions to this common problem.
If You are using Oracle 11g or newer, You can use PIVOT.
It is quite tricky to use.
You can write PL/SQL function that will return 'table' with all the data You want in any format You want.
You can Select one row with all months numbers from dual, then join them with Your query (preferably using WITH statement) 12 times (one for each month).
You can also realize that You do not need it in one row, because probably - You don't. :) maybe You can modify result where You get it from database, and then create one column for each month. Or maybe You can display it as a table and so on...
I think there are some other solutions as well, but I suggest You go for number 4.
I remember having similar problem quite often with SQL in the beginning, but they just fade away now.
I suppose You are approaching Your problem from wrong angle.

One approach, although verbose, is to define each aggregate column with a case statement as the argument to summarize. Then the "group by" and "order by" clauses only need to be given "id_agente" and "nombre". I've used this approach several times with Oracle data.
The below query is untested, and it makes some assumptions, but it should at least be a good start.
select a.id_agente id_agente,
a.NOMBRE nombre,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '01' then 1 else 0 end) ene,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '02' then 1 else 0 end) feb,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '03' then 1 else 0 end) mar,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '04' then 1 else 0 end) abr,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '05' then 1 else 0 end) may,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '06' then 1 else 0 end) jun,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '07' then 1 else 0 end) jul,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '08' then 1 else 0 end) ago,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '09' then 1 else 0 end) sep,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '10' then 1 else 0 end) oct,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '11' then 1 else 0 end) nov,
sum(case when to_char(to_date(dec.FECHA_RECOGIDA_ORIGEN,'dd/mm/yyyy'),'mm') = '12' then 1 else 0 end) dic
from dec
group by id_agente,
nombre
order by id_agente,
nombre;
However, using a pivot query, like Dark Anavger mentioned, would likely be the most formal approach if your output format needs to be a single row with twelve summary columns.
Good luck!

Related

12 months rolling

I have the query below which returns 12 months rolling data. So if I run it today it brings data back from 23rd August 2015 to 23rd August 2016. Now ideally I would like it to start from the 1st August 2015 and if I was to run it again next month it would start from 1stSeptember 2015. Is this possible to do? Thanks
select
Date
Street
Town
Incidents
IncidentType A
IncidentType B
IncidentType C
FROM
(
select
COUNT(I.INC_NUM) as Incidents,
COUNT(case when i.INC_TYPE = ''A'' THEN 1
end)
"IncidentType A"
COUNT(case when i.INC_TYPE = ''B'' THEN 1
end)
"IncidentType B"
COUNT(case when i.INC_TYPE = ''C'' THEN 1
end)
"IncidentType C"
FROM Table i
GROUP BY i.INC_NUM
) i
where Date >= (now()-('12 months'::interval))
Your code suggests that you are using Postgres. If the code works and you just need to adjust the where clause, use date_trunc():
where Date >= date_trunc('month', now() - ('12 months'::interval))

Using field alias in MSQuery does not work with DB2

This query works in data studio, but fails to show alias in MS Query!
I have tried different types such as "",'',[] and even https://support.microsoft.com/en-us/kb/298955
SELECT 'TRANIN'AS NAME, SUM(CASE WHEN ALT3.TRANINDT BETWEEN 20150603 AND 20150601 THEN 1 else 0 END) AS CurrentMonth, SUM(CASE WHEN ALT3.TRANINDT BETWEEN 20150501 AND 20150531 THEN 1 else 0 END) AS LastMonth
FROM ALT3
MS broke MS query a long time ago...
I've tried to get it to work right, but nothing worked. I've pretty much given up.
Normally I just rename the column once the data is back in Excel.
But if you really want the name returned from MS query, this works:
WITH tbl AS (SELECT 'TRANIN'AS NAME
, SUM(CASE WHEN ALT3.TRANINDT BETWEEN 20150603 AND 20150601
THEN 1 else 0 END) AS CurrentMonth
, SUM(CASE WHEN ALT3.TRANINDT BETWEEN 20150501 AND 20150531
THEN 1 else 0 END) AS LastMonth
FROM ALT3)
SELECT * FROM TBL

Union Statement that can be changed to Case statement

Good Day Everyone!
well i have this kind of code and it kinda ugly,
a friend of mine told me i can implement Case Statements in here, but i do not know how or how would i implement, the code is long so if you could just help me to optimize my code i would appreciate it greatly!
PS. please be gentle to me, im new in T-sql :)
Thank yoU!
SELECT
SUM(CYJEWELRY) 'CY_Jewelry'
,SUM(CYAPPLICANCE) 'CY_Appliance'
,SUM(CYCELLPHONE) 'CY_Cellphone'
,SUM(PYJEWELRY) 'PY_Jewelry'
,SUM(PYAPPLIANCE) 'PY_Appliance'
,SUM(PYCELLPHONE) 'PY_Cellphone'
FROM
(
---TOTAL NUNG A FORMAT 0,0,0,0,0,0
--------------CURRENT YEAR JEWELRY
SELECT COUNT (*) AS CYJEWELRY,0 AS CYAPPLICANCE,0 AS CYCELLPHONE,0 AS PYJEWELRY,0 AS PYAPPLIANCE,0 AS PYCELLPHONE
FROM #TEMPTABLE1
WHERE (fld_StorageGroupID >= 3 and fld_StorageGroupID <= 14)
UNION
-----------CURRENT YEAR APPLIANCE
SELECT 0,COUNT(*),0,0,0,0
FROM #TEMPTABLE1
WHERE fld_StorageGroupID = 1
UNION
------------CURRENT YEAR CELLPHONE
SELECT 0,0,COUNT(*),0,0,0
FROM #TEMPTABLE1
WHERE fld_StorageGroupID = 2
UNION
---------------LAST YEAR JEWELRY
SELECT 0,0,0,COUNT(*),0,0
FROM #TEMPTABLE2
WHERE (fld_StorageGroupID >= 3 and fld_StorageGroupID <= 14)
UNION
-----------------------LAST YEAR APPLIANCE
SELECT 0,0,0,0,COUNT (*),0
FROM #TEMPTABLE2
WHERE fld_StorageGroupID = 1
UNION
-------------------------LAST YEAR CELLPHONE
SELECT 0,0,0,0,0,COUNT(*)
FROM #TEMPTABLE2
WHERE fld_StorageGroupID = 2
)A
Assuming your data is bit like this Sql Fiddle Example, try this for the sub query using SUM() and CASE.
SELECT SUM(CASE WHEN fld_StorageGroupID >= 3 and fld_StorageGroupID <= 14 ELSE 0 END) Col1And4,
SUM(CASE WHEN fld_StorageGroupID = 1 THEN 1 ELSE 0 END) Col2And5,
SUM(CASE WHEN fld_StorageGroupID = 2 THEN 1 ELSE 0 END) Col3And6
FROM #TEMPTABLE1
GROUP BY fld_StorageGroupID
Since you are applying the same filter for last 3 columns in the subquery, I have done only first 3 columns here.
EDIT:
I think this is better than above (Note: no need to use SUM() in the main query).
Fiddle Example with data
select col1_4 CY_Jewelry,
col2_5 CY_Appliance,
col3_6 CY_Cellphone,
col1_4 PY_Jewelry,
col2_5 PY_Appliance,
col3_6 PY_Cellphone
from (
select sum(case when id>= 3 and id <= 14 then 1 else 0 end) col1_4,
sum(case when id = 2 then 1 else 0 end) col2_5,
sum(case when id = 3 then 1 else 0 end) col3_6
from t
--group by id
) X

Remove group by field

I've got an issue while getting data from DB2. I want to summarise the invoice amounts by customer. In one field, (calculated - I've called this InvoicedThisYear) it works out what was invoiced this year and in another it works out what was invoiced in the previous year (calculated, I've called it InvoicedLastYear). However, as it is summariesed I've grouped it by the Cust, but it is also wanting the data grouped by the InvoiceYear, so I've had to include this in the grouping. My problem is in my results I now have zeros for the years where there is no data and duplicates, e.g.:
Cust InvoicedThisYear InvoiceLastYear
abc 0 100
abc 100 0
Ideally I would like to see
Cust InvoicedThisYear InvoicedLastYear
abc 100 100
Here is my code:
SELECT
Cust AS Customer,
(CASE WHEN InvoiceYear = Year(Current Date) THEN sum(InvoiceAmt)ELSE 0 END) as InvoicedThisYear,
(CASE WHEN InvoiceYear = year(Current Date)-1 THEN sum(InvoiceAmt)ELSE 0 END) as InvoicedLastYear
FROM
InvHead
GROUP BY
Cust,
InvoiceYear
HAVING
((CASE WHEN InvoiceYear = Year(Current Date) THEN sum(InvoiceAmt)ELSE 0 END)<>0)
OR
((CASE WHEN InvoiceYear = year(Current Date)-1 THEN sum(InvoiceAmt)ELSE 0 END)<>0)
ORDER BY
Cust
How do I get the desired result? The query will not run if I remove the groupby Invoice Year
As a size note, it works in MS Access without grouping by the Invoice Year!
Thanks,
Michael
You need to put the SUM() around the case statements:
SELECT
Cust AS Customer,
sum(CASE WHEN InvoiceYear = Year(Current Date) THEN InvoiceAmt ELSE 0 END) as InvoicedThisYear,
sum(CASE WHEN InvoiceYear = year(Current Date)-1 THEN InvoiceAmt ELSE 0 END) as InvoicedLastYear
FROM
InvHead
GROUP BY
Cust
ORDER BY
Cust

Count orders by days of the week, adding Saturday & Sunday counts to Friday

I would like to get the count of ordered items from monday to sunday but adding saturday and sunday orders to fridays, so the query results would only display Orderdates (Monday to Friday)
I have this sql already that shows orders for every single day of the week:
select DATENAME(weekday,orderdate) Day,CONVERT(VARCHAR(10), orderdate, 103) orderdate,
COUNT(orderdate) Orders
from Orders_tb
where orderDate >= '2012-03-01 00:00:00.000'
and orderDate <= '2012-03-31 00:00:00.000'
group by datepart(day,orderDate),orderdate,DATENAME(weekday,orderdate)
Thanks for your input!
EDIT after clarification.
Use case to change weekend days to friday. Derived table is employed to avoid the need to replicate the same expression everywhere orderdate is needed.
select DATENAME(weekday,orderdate_trimmed) Day,
CONVERT(VARCHAR(10), orderdate_trimmed, 103) orderdate,
COUNT(orderdate_trimmed) Orders
from
(
select *,
order_date -
case DATENAME(weekday,orderdate)
when 'Saturday' then 1
when 'Sunday' then 2
else 0
end
orderdate_trimmed
from Orders_tb
) a
where orderDate >= '2012-03-01 00:00:00.000'
and orderDate <= '2012-03-31 00:00:00.000'
group by orderdate_trimmed
You might count matching days only by use of case statement:
select COUNT(orderdate) TotalOrders,
COUNT(CASE WHEN DATENAME(weekday,orderdate) = 'Monday' then 1 end) Monday,
COUNT(CASE WHEN DATENAME(weekday,orderdate) = 'Tuesday' then 1 end) Tuesday,
COUNT(CASE WHEN DATENAME(weekday,orderdate) = 'Wednesday' then 1 end) Wednesday,
COUNT(CASE WHEN DATENAME(weekday,orderdate) = 'Thursday' then 1 end) Thursday,
COUNT(CASE WHEN DATENAME(weekday,orderdate) = 'Friday'
OR DATENAME(weekday,orderdate) = 'Saturday'
OR DATENAME(weekday,orderdate) = 'Sunday'
THEN 1 end) Friday
from Orders_tb
where orderDate >= '2012-03-01 00:00:00.000'
and orderDate <= '2012-03-31 00:00:00.000'
A warning about dates: as a date can contain time portion it would be wiser to compare like this:
where orderDate >= '2012-03-01 00:00:00.000'
and orderDate < '2012-04-01 00:00:00.000'