SQL Joined Tables - Multiple rows on joined table per 'on' matched field merged into one row? - sql

I have two tables I am pulling data from. Here is a minimal recreation of what I have:
Select
Jobs.Job_Number,
Jobs.Total_Amount,
Job_Charges.Charge_Code,
Job_Charges.Charge_Amount
From
DB.Jobs
Inner Join
DB.Job_Charges
On
Jobs.Job_Number = Job_Charges.Job_Number;
So, what happens is that I end up getting a row for each different Charge_Code and Charge_Amount per Job_Number. Everything else on the row is the same. Is it possible to have it return something more like:
Job_Number - Total_Amount - Charge_Code[1] - Charge_Amount[1] - Charge_Code[2] - Charge_Amount[2]
ETC?
This way it creates one line per job number with each associated charge and amount on the same line. I have been reading through W3 but haven't been able to tell definitively if this is possible or not. Anything helps, thank you!

To pivot your resultset over a fixed number of columns, you can use row_number() and conditional aggregation:
select
job_number,
total_amount,
max(case when rn = 1 then charge_code end) charge_code1,
max(case when rn = 1 then charge_amount end) charge_amount1,
max(case when rn = 2 then charge_code end) charge_code2,
max(case when rn = 2 then charge_amount end) charge_amount2,
max(case when rn = 3 then charge_code end) charge_code3,
max(case when rn = 3 then charge_amount end) charge_amount3
from (
select
j.job_number,
j.total_amount,
c.charge_code,
c.charge_amount,
row_number() over(partition by job_number, total_amount order by c.charge_code) rn
from DB.Jobs j
inner join DB.Job_Charges c on j.job_number = c.job_number
) t
group by job_number, total_amount
The above query handes up to 3 charge codes and amounts par job number (ordered by job codes). You can expand the select clause with more max(case ...) expressions to handle more of them.

Related

How to do this query using self join or anything but without using window function

Below is the solution but I want to know other ways to accomplish the same results (preferably in PostgreSQL).
This is the DB
Question - How many customers have churned straight after their initial free trial? what percentage is this rounded to the
nearest whole number?
WITH ranking AS (
SELECT
s.customer_id,
s.plan_id,
p.plan_name,
ROW_NUMBER() OVER (
PARTITION BY s.customer_id
ORDER BY s.plan_id) AS plan_rank
FROM dbo.subscriptions s
JOIN dbo.plans p
ON s.plan_id = p.plan_id)
SELECT
COUNT(*) AS churn_count,
ROUND(100 * COUNT(*) / (
SELECT COUNT(DISTINCT customer_id)
FROM dbo.subscriptions),0) AS churn_percentage
FROM ranking
WHERE plan_id = 4 -- Filter to churn plan
AND plan_rank = 2
You can achieve the same results with a single aggregation on customer_id with a few CASE WHEN statements:
SELECT count(*) as total_customers
,count(case when total_subscriptions = 2
and includes_free = 1
and includes_churn = 1 then 1 end) as churn_count
,100 * count(case when total_subscriptions = 2
and includes_free = 1
and includes_churn = 1 then 1 end) / count(*) as target_percent
FROM (
SELECT customer_id
,count(*) as total_subscriptions
,max(case when plan_id = 0 then 1 else 0 end) as includes_free
,max(case when plan_id = 4 then 1 else 0 end) as includes_churn
FROM dbo.subscriptions
GROUP BY customer_id
) AS tbl
-- Remove any records for people who didnt use the free trial
-- or people who are still on the free trial
WHERE includes_free = 1 AND total_subscriptions > 1
The difference between our solutions are:
Yours doesn't specify that the customer actually had a free trial
Mine doesn't include customers who went from Free -> Churn -> (something else)
Depending on your requirements you might want to make further alterations/use a different approach.

One-to-many query

I have an hypothetical database as the image below were each plant can have a maximum of 4 colours.
I wish to be able to return my results in a format similar to the below.
If I run a standard query with Inner Join the results are duplicated were the plant has more than one colour. I have therefore tried running multiple separate queries were I first return the plant then a new query to return the colours. I then loop though colour result to produce the output I desire.
I assume there is a far for efficient way to achieve this?
I am trying to do this as a query and as a stored procedure so any pointers would be much appreciated.
If you know there are a maximum of 4 colors, then you can use row_number() and conditional aggregation:
select plantname,
max(case when seqnum = 1 then colorname end) as color_1,
max(case when seqnum = 2 then colorname end) as color_2,
max(case when seqnum = 3 then colorname end) as color_3,
max(case when seqnum = 4 then colorname end) as color_4
from (select p.plantname, p.plantid, c.colorname,
row_number() over (partition by p.plantid order by c.colorid) as seqnum
from plants p join
plantcolors pc
on pc.plantid = p.plantid join
colors c
on pc.colorid = c.colorid
) pc
group by plantname, plantid;

T-SQL query Fetching data in a single line where multiple rows have similar filters

We have a table in which I'm having 2 lines with the similar document no. and line no. in which I want the values in a single line in which I can see some values of other lines.
Original dataset
As attached in screen I have doc no. and line no is same in 2 lines and if I need values from 2nd line that should look like the second screenshot.
Result image should be:
You can define the row_numbers using row_number() function based on GST Component or Entry_no as because there are three type of GST's CGST-SGST-IGST moreover the other is UGST which is related to any union territory.
select max(case when entryno = 1 then 1 end) as Entry_no, doc,
max(case when entryno = 1 then GSTComp end) as GSTComp1,
max(case when entryno = 1 then [GST%] end) as [GST%1],
max(case when entryno = 1 then GSTAmt end) as GSTAmt1,
. . .
max(case when entryno = 3 then GSTAmt end) as GSTComp3
from (select *, row_number() over (partition by doc order by entryno) as seq
from table
) t
group by doc;
SELECT
t1.Entry_no
, t1.doc
, t1.GSTComp
, t1.GST%
, t1.GSTAmt
, t2.GSTComp as t2.GSTComp2
, t2.GSTAmt as t2.GSTAmt2
FROM table t1 INNER JOIN table t2
ON t1.doc = t2.doc and t1.lin = t2.lin
Try this query

lookup and sum contracts in DB2 SQL

I'm trying to compute the value of the contract amendments in this below table.
when there is an amendment to an contract the value is updated with the remainder from the last version of the contract + the value added in the amendment.
To illustrate i added the info on how its calculated in the last column.
How would I go about that in SQL for DB2, I'm hitting a wall here.
Thanks
Consider using a self join each calculating running number by Contract with ROW_NUMBER() . Specifically, have the LEFT JOIN filtered to one row number behind the first FROM table. From there columns will align for AmendmentValue calculation:
SELECT sub1.Contract, sub1.Amendment, sub1.Value, sub1.Billed, sub1.Reminder,
(CASE WHEN sub1.Amendment IS NULL THEN NULL
ELSE sub1.Billed - sub2.Remainder END) As AmendmentValue
FROM
(SELECT t.Contract, t.Amendment, t.Value, t.Billed, t.Remainder,
ROW_NUMBER() OVER (PARTITION BY t.Contract
ORDER BY CASE WHEN t.Amendment IS NULL THEN 1 ELSE t.Amendment END) rn
FROM TableName t) sub1
LEFT JOIN
(SELECT t.Contract, t.Amendment, t.Value, t.Billed, t.Remainder,
ROW_NUMBER() OVER (PARTITION BY t.Contract
ORDER BY CASE WHEN t.Amendment IS NULL THEN 1 ELSE t.Amendment END) rn
FROM TableName t) sub2
ON sub1.Contract = sub2.Contract AND sub1.rn = sub2.rn + 1

pivot table returns more than 1 row for the same ID

I have a sql code which I am using to do pivot. Code is as follows:
SELECT DISTINCT PersonID
,MAX(pivotColumn1)
,MAX(pivotColumn2) --originally these were in 2 separate rows)
FROM(SELECT srcID, PersonID, detailCode, detailValue) FROM src) AS SrcTbl
PIVOT(MAX(detailValue) FOR detailCode IN ([pivotColumn1],[pivotColumn2])) pvt
GROUP BY PersonID
In the source data the ID has 2 separate rows due to having its own ID which separates the values. I have now pivoted it and its still giving me 2 separate rows for the ID even though i grouped it and used aggregation on the pivot columns. Ay idea whats wrong with the code?
So I have all my possible detailCode listed in the IN clause. So I have null returned when the value is none but I want it all summarised in 1 row. See image below.
If those are all the options of detailCode , you can use conditional aggregation with CASE EXPRESSION instead of Pivot:
SELECT t.personID,
MAX(CASE WHEN t.detailCode = 'cas' then t.detailValue END) as cas,
MAX(CASE WHEN t.detailCode = 'buy' then t.detailValue END) as buy,
MAX(CASE WHEN t.detailCode = 'sel' then t.detailValue END) as sel,
MAX(CASE WHEN t.detailCode = 'pla' then t.detailValue END) as pla
FROM YourTable t
GROUP BY t.personID