Show Rows Data Into Column Wise - postgresql

i wants to show rows data into columns. suppose if rows type increased then number of columns also increased. Information as follow:
Please see picture to get idea

You can use COUNT with CASE WHEN:
SELECT t.Name AS Type,
COUNT(*) AS NumberOfCase,
COUNT(CASE WHEN s.Name = 'Resolved' THEN 1 END) AS Resolved,
COUNT(CASE WHEN s.Name = 'Pending' THEN 1 END) AS Pending,
COUNT(CASE WHEN s.Name = 'Waiting' THEN 1 END) AS Waiting
FROM Type t
LEFT JOIN "Case" c
ON c.CaseType = t.TypeId
LEFT JOIN "Status" s
ON c.CaseStatus = s.StatusId
GROUP BY t.Name;
SqlFiddleDemo

Related

Need help rewriting a T-SQL query for results to get displayed in a stacked bar

I have come up with the following query which gives rise to the below result.
SELECT TOP (100) PERCENT s.UserfName AS ASSIGNEE, e.status, COUNT(*) AS [TOTAL COUNT], CASE WHEN e.status = "Open" THEN 'OPEN' END AS
FROM dbo.t_helpdesktickets AS e INNER JOIN
dbo.t_assetusers AS s ON e.currentlyat = s.UserID
WHERE (e.status IN ('open', 'closed'))
GROUP BY s.UserfName, e.status
How will I rewrite my query to return results as below
Use conditional aggregation:
SELECT
s.UserfName AS ASSIGNEE,
COUNT(CASE WHEN e.status = 'open' THEN 1 END) AS "OPEN",
COUNT(CASE WHEN e.status = 'closed' THEN 1 END) AS "CLOSED"
FROM dbo.t_assetusers AS s
LEFT JOIN dbo.t_helpdesktickets AS e
ON e.currentlyat = s.UserID
GROUP BY
s.UserfName;
Note that I switched to using a left join here, in case certain users might not have any records corresponding to either of the two statuses. Using this approach, the open/closed counts would then show up as zero.

How to shorten loading time with multiple subqueries and joins?

I have a query to find which v_address belonged to which v_group, and when was the creation date of v_address. However, each v_group was sometimes active and inactive and it has dates. So, I wrote query to find the period of those changes.
My problem is my query took too long time to run because it has multiple subqueries and joins.
Does anyone have a better idea to shorten to load data?
I attached my query below identifier = 81 is for smaller testing. For the final result, I will need to retrieve data for more than 100k ids.
I tried to change inner joins to left joins but it loses null values and still took too long time to retrieve data.
with v_address as (
select id, v_group_id, created_at
from prod.venue_address --different schema and table. v_address.v_group_id can have multiple v_address.id
group by 1,2,3
order by 3 asc
),
v_group as (
select identifier, final_status, created_at
from dwh.venue_address_archive
where identifier = 81
group by 1,2,3
order by 3 asc
),
filtering as (
select identifier, created_at,
case when sum(case when final_state = 'active' then 1 else 0 end) > 0 then 'active' else 'inactive' end as filtered_status --This filters either of active or inactive
from v_group
group by 1,2
order by 2 asc
),
prev as (
select identifier, created_at, filtered_status,
lag(case when filtered_status = 'active' then 'active' else 'inactive' end) over (partition by identifier order by created_at) = filtered_status as is_prev_status
from filtering
group by 1,2,3
),
periods as (
select identifier, filtered_status, created_at, is_prev_status,
sum(case when is_prev_status = true then 0 else 1 end) over (order by identifier, created_at) as period
from prev
group by 1,2,3,4
),
islands_gaps_start as (
select identifier, period, min(created_at) as start_at
from periods
group by 2,1
),
islands_gaps as (
select identifier, period, start_at,
lead(start_at) over (partition by identifier order by period) as end_at
from islands_gaps_start
)
select vg.identifier as "vg_id", p.created_at as "vg_created_at", p.filtered_status as "status", p.is_prev_status, p.period, va.id as "va_id", g.start_at, g.end_at
from v_address va
left join v_group vg
on va.venue_id = vg.identifier
inner join filtering f
on vg.identifier = f.identifier
inner join prev pr
on pr.filtered_status = f.filtered_status
inner join periods p
on p.filtered_status = pr.filtered_status
inner join islands_gaps_start gs
on p.period = gs.period
inner join islands_gaps g
on gs.start_at = g.start_at
group by 6,1,2,3,4,5,7,8
order by 2 asc
I already have the output with an example identifier = 81 but I have to run this query for more than 100k identifiers so, I'm looking for any advice that I can shorten my query.

Query where ALL associated records have attribute value X

I have a query that counts associated records AND associated status
SELECT
orders.id,
SUM(CASE WHEN s.shipment_status='CLOSED' THEN 1 ELSE 0 END) as closed,
COUNT(*) as shipment_count
FROM orders as po
JOIN shipments as s ON s.order_id = po.id
GROUP BY po.id
I am attempting to query all orders, where all the shipments are CLOSED.
Essentially looking at the above, just returning when closed = shipment_count .
If I add an AND clause to the join then it will simply limit the number of shipments.
I figured this out with a HAVING clause, which doesn't use the select attrs.
SELECT
orders.id
FROM orders as po
JOIN shipments as s ON s.order_id = po.id
GROUP BY po.id
HAVING SUM(CASE WHEN s.shipment_status='CLOSED' THEN 1 ELSE 0 END) = COUNT(*)
Leaving my answer up in case it helps others. Maybe better answers available to come from the community.

how to select top 10 without duplicates

Using SQL Server 2012
I need to select TOP 10 Producer based on a ProducerCode. But the data is messed up, users were entering same Producers just spelled differently and with the same ProducerCode.
So I just need TOP 10, so if the ProducerCode is repeating, I just want to pick the first one in a list.
How can I achieve that?
Sample of my data
;WITH cte_TopWP --T
AS
(
SELECT distinct ProducerCode, Producer,SUM(premium) as NetWrittenPremium,
SUM(CASE WHEN PolicyType = 'New Business' THEN Premium ELSE 0 END) as NewBusiness1,
SUM(CASE WHEN PolicyType = 'Renewal' THEN Premium ELSE 0 END) as Renewal1,
SUM(CASE WHEN PolicyType = 'Rewrite' THEN Premium ELSE 0 END) as Rewrite1
FROM ProductionReportMetrics
WHERE YEAR(EffectiveDate) = 2016 AND TransactionType = 'Policy' AND CompanyLine = 'Arch Insurance Company'--AND ProducerType = 'Wholesaler'
GROUP BY ProducerCode,Producer
)
,
cte_Counts --C
AS
(
SELECT distinct ProducerCode, ProducerName, COUNT (distinct ControlNo) as Submissions2,
SUM(CASE WHEN QuotedPremium IS NOT NULL THEN 1 ELSE 0 END) as Quoted2,
SUM(CASE WHEN Type = 'New Business' AND Status IN ('Bound','Cancelled','Notice of Cancellation') THEN 1 ELSE 0 END ) as NewBusiness2,
SUM(CASE WHEN Type = 'Renewal' AND Status IN ('Bound','Cancelled','Notice of Cancellation') THEN 1 ELSE 0 END ) as Renewal2,
SUM(CASE WHEN Type = 'Rewrite' AND Status IN ('Bound','Cancelled','Notice of Cancellation') THEN 1 ELSE 0 END ) as Rewrite2,
SUM(CASE WHEN Status = 'Declined' THEN 1 ELSE 0 END ) as Declined2
FROM ClearanceReportMetrics
WHERE YEAR(EffectiveDate)=2016 AND CompanyLine = 'Arch Insurance Company'
GROUP BY ProducerCode,ProducerName
)
SELECT top 10 RANK() OVER (ORDER BY NetWrittenPremium desc) as Rank,
t.ProducerCode,
c.ProducerName as 'Producer',
NetWrittenPremium,
t.NewBusiness1,
t.Renewal1,
t.Rewrite1,
c.[NewBusiness2]+c.[Renewal2]+c.[Rewrite2] as PolicyCount,
c.Submissions2,
c.Quoted2,
c.[NewBusiness2],
c.Renewal2,
c.Rewrite2,
c.Declined2
FROM cte_TopWP t --LEFT OUTER JOIN tblProducers p on t.ProducerCode=p.ProducerCode
LEFT OUTER JOIN cte_Counts c ON t.ProducerCode=c.ProducerCode
You should use ROW_NUMBER to fix your issue.
https://msdn.microsoft.com/en-us/library/ms186734.aspx
A good example of this is the following answer:
https://dba.stackexchange.com/a/22198
Here's the code example from the answer.
SELECT * FROM
(
SELECT acss_lookup.ID AS acss_lookupID,
ROW_NUMBER() OVER
(PARTITION BY your_distinct_column ORDER BY any_column_you_think_is_appropriate)
as num,
acss_lookup.product_lookupID AS acssproduct_lookupID,
acss_lookup.region_lookupID AS acssregion_lookupID,
acss_lookup.document_lookupID AS acssdocument_lookupID,
product.ID AS product_ID,
product.parent_productID AS productparent_product_ID,
product.label AS product_label,
product.displayheading AS product_displayheading,
product.displayorder AS product_displayorder,
product.display AS product_display,
product.ignorenewupdate AS product_ignorenewupdate,
product.directlink AS product_directlink,
product.directlinkURL AS product_directlinkURL,
product.shortdescription AS product_shortdescription,
product.logo AS product_logo,
product.thumbnail AS product_thumbnail,
product.content AS product_content,
product.pdf AS product_pdf,
product.language_lookupID AS product_language_lookupID,
document.ID AS document_ID,
document.shortdescription AS document_shortdescription,
document.language_lookupID AS document_language_lookupID,
document.document_note AS document_document_note,
document.displayheading AS document_displayheading
FROM acss_lookup
INNER JOIN product ON (acss_lookup.product_lookupID = product.ID)
INNER JOIN document ON (acss_lookup.document_lookupID = document.ID)
)a
WHERE a.num = 1
ORDER BY product_displayheading ASC;
You could do this:
SELECT ProducerCode, MIN(Producer) AS Producer, ...
GROUP BY ProducerCode

Help with difficult 'group by' clause

need some your help with a query.
I have a table Managers (ManagerId, ManagerName)
I have a table Statuses (StatusId, StatusName)
(There's about 10 statuses in that table)
I have a table Clients (ClientId, ClientName, ManagerId, StatusId, WhenAdded)
(WhenAdded is a datetime type)
It's obvious that field 'ManagerId' refers to a table 'Managers' and field 'StatusId' refers to a table 'Statuses'.
User wants to get some statistics about Managers over a period of time (from startDate to endDate using field 'WhenAdded') in the following table.
Columns:
ManagerName, NumberOfClients, NumberOfClientsWithStatus1, NumberOfClientsWithStatus2, NumberOfClientsWithStatus3 and so on.
Number of columns with name NumberOfClientsWithStatusI where i is a number of statuses equal to number of rows in table 'Statuses'.
How can I do that?
t-sql, sql server 2008 r2 express edition.
SELECT
ManagerName,
COUNT(*) AS NumberOfClients,
COUNT(CASE WHEN S.StatusId = 1 THEN 1 ELSE NULL END) AS NumberOfClientsWithStatus1,
COUNT(CASE WHEN S.StatusId = 2 THEN 1 ELSE NULL END) AS NumberOfClientsWithStatus2,
COUNT(CASE WHEN S.StatusId = 3 THEN 1 ELSE NULL END) AS NumberOfClientsWithStatus3,
...
FROM
Clients C
JOIN
Managers M ON C.ManagerId = M.ManagerId
JOIN
Statuses S ON C.StatusId = S.StatusId
WHERE
M.WhenAdded BETWEEN #startDate AND #endDate
GROUP BY
M.ManagerName
Note: there is no clean way to add arbritrary numbers of status columns in SQL (not just SQL Server) because its a fixed column output. You'd have to change the query for status, unless you deal with this in the client
Edit, after comment
SELECT
ManagerName,
COUNT(*) AS NumberOfClients,
COUNT(CASE WHEN S.StatusId = 1 THEN 1 ELSE NULL END) AS NumberOfClientsWithStatus1,
COUNT(CASE WHEN S.StatusId = 2 THEN 1 ELSE NULL END) AS NumberOfClientsWithStatus2,
COUNT(CASE WHEN S.StatusId = 3 THEN 1 ELSE NULL END) AS NumberOfClientsWithStatus3,
...
FROM
Managers M ON C.ManagerId = M.ManagerId
LEFT JOIN
Clients C
LEFT JOIN
Statuses S ON C.StatusId = S.StatusId
WHERE
M.WhenAdded BETWEEN #startDate AND #endDate
GROUP BY
M.ManagerName
If you know that statuses table will always contain a limited number of statuses, you can do this:
SELECT M.ManagerName,
COUNT(C.ClientId) NumberOfClients,
SUM(CASE WHEN S.StatusId= 1 THEN 1 ELSE 0 END) NumberOfClientsWithStatus1,
SUM(CASE WHEN S.StatusId= 2 THEN 1 ELSE 0 END) NumberOfClientsWithStatus2,
...
FROM Clients C
JOIN Managers M on M.ManagerId = C.ManagerId
JOIN Statuses S on S.StatusId = C.StatusId
WHERE C.WhenAdded BETWEEN startDate AND endDate
GROUP BY ManagerName