Sql Pivot and Unpivot - sql

a newbie here..Actually I have a table in Oracle vw_summary as
Onum | Uacheck | Uadesc | AU11 | AU12 | BD10 |
----------------------------------------------------------
1 | 5.1 | VENDOR | 0 | 0 | 0 |
2 | 5.2A | CUST | 0 | 0 | 0 |
and I need data displayed as:-
Onum | PLant | 5.1 - VENDOR | 5.2A - CUST
---------------------------------------------------
1 | AU11 | 0 | 0
2 | AU12 | 0 | 0
3 | BD10 | 0 | 0
i.e. I need the columns AU11, AU12, BD10 to become rows of my Plant column
and each concatenation of UACHECK || UADESC TO BECOME ROWS.

Try this:
WITH T1 AS (SELECT *
FROM vw_summary UNPIVOT (plantvalue
FOR plant
IN (AU11, AU12, BD10))),
T2
AS (SELECT UACHECK,
UADESC,
PLANT,
PLANTVALUE,
ROW_NUMBER () OVER (PARTITION BY UADESC ORDER BY UADESC)
AS NUM
FROM T1)
SELECT *
FROM t2 PIVOT (MIN (PLANTVALUE)
FOR (UADESC, UACHECK)
IN ( ('VENDOR', '5.1') AS "5.1 - VENDOR",
('CUST', '5.2A') AS "5.2A - CUST"));

Related

Replace null values with most recent non-null values SQL

I have a table where each row consists of an ID, date, variable values (eg. var1).
When there is a null value for var1 in a row, I want like to replace the null value with the most recent non-null value before that date for that ID. How can I do this quickly for a very large table?
So presume I start with this table:
+----+------------|-------+
| id |date | var1 |
+----+------------+-------+
| 1 |'01-01-2022'|55 |
| 2 |'01-01-2022'|12 |
| 3 |'01-01-2022'|45 |
| 1 |'01-02-2022'|Null |
| 2 |'01-02-2022'|Null |
| 3 |'01-02-2022'|20 |
| 1 |'01-03-2022'|15 |
| 2 |'01-03-2022'|Null |
| 3 |'01-03-2022'|Null |
| 1 |'01-04-2022'|Null |
| 2 |'01-04-2022'|77 |
+----+------------+-------+
Then I want this
+----+------------|-------+
| id |date | var1 |
+----+------------+-------+
| 1 |'01-01-2022'|55 |
| 2 |'01-01-2022'|12 |
| 3 |'01-01-2022'|45 |
| 1 |'01-02-2022'|55 |
| 2 |'01-02-2022'|12 |
| 3 |'01-02-2022'|20 |
| 1 |'01-03-2022'|15 |
| 2 |'01-03-2022'|12 |
| 3 |'01-03-2022'|20 |
| 1 |'01-04-2022'|15 |
| 2 |'01-04-2022'|77 |
+----+------------+-------+
cte suits perfect here
this snippets returns the rows with values, just an update query and thats all (will update my response).
WITH selectcte AS
(
SELECT * FROM testnulls where var1 is NOT NULL
)
SELECT t1A.id, t1A.date, ISNULL(t1A.var1,t1B.var1) varvalue
FROM selectcte t1A
OUTER APPLY (SELECT TOP 1 *
FROM selectcte
WHERE id = t1A.id AND date < t1A.date
AND var1 IS NOT NULL
ORDER BY id, date DESC) t1B
Here you can dig further about CTEs :
https://learn.microsoft.com/en-us/sql/t-sql/queries/with-common-table-expression-transact-sql?view=sql-server-ver16

How to use SQL Join with multiple fields and find sum of values

How to SQL Join with multiple fields and sum of values .
As per my query i am getting duplicates
job_main (table)
+-----+------+------+------------+
| Loc | Year | Wo | total_cost |
+-----+------+------+------------+
| 8 | 2018 | 2402 | 1175 |
+-----+------+------+------------+
Job_line (table)
+-----+------+------+------------+------------+-----------+-----------+-----------+
| loc | Year | Wo | labor_cost | parts_cost | total_tax | parts_tax | labor_tax |
+-----+------+------+------------+------------+-----------+-----------+-----------+
| 8 | 2018 | 2402 | 0 | 1202.85 | 0 | 0 | 0 |
| 8 | 2018 | 2402 | 0 | -1202.85 | 0 | 0 | 0 |
| 8 | 2018 | 2402 | 0 | 1119.05 | 55.95 | 55.95 | 0 |
+-----+------+------+------------+------------+-----------+-----------+-----------+
Result (Expected)
+-----+------+------+------------+------------+------------+-----------+-----------+-----------+
| Loc | Year | Wo | total_cost | labor_cost | parts_cost | parts_tax | labor_tax | total_tax |
+-----+------+------+------------+------------+------------+-----------+-----------+-----------+
| 8 | 2018 | 2402 | 1175 | 0 | 1119.05 | 55.95 | 0 | 55.95 |
+-----+------+------+------------+------------+------------+-----------+-----------+-----------+
My Query:
SELECT distinct "JOB_LINE""."LOC", "JOB_LINE""."Year", "JOB_LINE""."Wo"
, ISNULL(("JOB_MAIN"."total_cost" ), 0) AS "total_cost", ISNULL(SUM("JOB_LINE""."labor_cost"), 0) AS "labor_cost"
, ISNULL(SUM("JOB_LINE""."labor_tax"), 0) AS "labor_tax" , ISNULL(SUM("JOB_LINE""."parts_cost"), 0) AS "parts_cost"
, ISNULL(SUM("JOB_LINE""."total_tax"), 0) AS "total_tax" , ISNULL(SUM("JOB_LINE""."parts_tax"), 0) AS "parts_tax"
FROM "proto"."emsdba"."JOB_LINE"" "JOB_LINE""
INNER JOIN "proto"."emsdba"."JOB_MAIN" "JOB_MAIN"
ON "JOB_LINE"".LOC="JOB_MAIN".LOC AND "JOB_LINE"".year="JOB_MAIN".year AND "JOB_LINE"".Wo="JOB_MAIN".Wo
GROUP by "JOB_LINE""."LOC", "JOB_LINE""."Year", "JOB_LINE""."Wo","JOB_MAIN"."total_cost"
, "JOB_LINE"".labor_cost, "JOB_LINE"".parts_cost, "JOB_LINE"".total_tax, "JOB_LINE"".parts_tax,"JOB_LINE"".labor_tax
Try with this:
select m.loc,m.year,m.wo,m.total_cost,sum(l.labor_cost),sum(l.parts_cost),sum(l.parts_tax),sum(l.labor_tax),sum(l.total_tax)
from proto.emsdba.job_main m
join proto.emsdba.job_line l
on m.loc=l.loc
and m.year=l.year
and m.wo=l.wo
group by m.loc,m.year,m.wo,m.total_cost
Basically, you group by the fields in the parent table (shared by all the lines) and sum the values of the lines to get a single record for each key (loc/year/wo)
Although you can use join and group by for this, this problem is also a good candidate for apply:
select m.*,
coalesce(labor_cost, 0) as labor_cost,
coalesce(parts_cost, 0) as parts_cost,
coalesce(parts_tax, 0) as parts_tax,
coalesce(labor_tax, 0) as labor_tax,
coalesce(total_tax, 0) as total_tax
from proto.emsdba.job_main m outer apply
(select sum(jl.labor_cost) as labor_cost,
sum(jl.parts_cost) as parts_cost,
sum(jl.parts_tax) as parts_tax,
sum(jl.labor_tax) as labor_tax,
sum(jl.total_tax) as total_tax
from proto.emsdba.job_line jl
where m.loc = jl.loc and
m.year = jl.year and
m.wo = jl.wo
) jl;

Different aggregation fields in same query

I am trying to aggregate some fields in different way - using partition - in the same query but found a problem with AVG():
Take this definition:
CREATE TABLE Result
(CheckListId int, CheckId int, AuditId int, CheckListResult FLOAT, CheckResult FLOAT)
INSERT INTO Result VALUES (1,1,1,1,1)
INSERT INTO Result VALUES (1,2,1,1,3)
INSERT INTO Result VALUES (1,2,2,3,1)
INSERT INTO Result VALUES (2,1,1,3,1)
+-------------+---------+---------+-----------------+-------------+
| CheckListId | CheckId | AuditId | CheckListResult | CheckResult |
+-------------+---------+---------+-----------------+-------------+
| 1 | 1 | 1 | 1 | 1 |
| 1 | 2 | 1 | 1 | 3 |
| 1 | 2 | 2 | 3 | 1 |
| 2 | 1 | 1 | 3 | 1 |
+-------------+---------+---------+-----------------+-------------+
thanks to Format Text as Table for formatting
this is my select
SELECT
CheckListId
, CheckId
, (dense_rank() over (PARTITION BY CheckListId order by [AuditId])
+ dense_rank() over (PARTITION BY CheckListId order by [AuditId] desc)
- 1) AS N_AuditForCheckList
, AVG(CheckListResult) OVER(PARTITION BY CheckListId) AS AvgCheckListResult
, COUNT(AuditId) OVER (PARTITION BY CheckListId, CheckId) AS N_AuditForCheck
, AVG(CheckResult) OVER(PARTITION BY CheckListId, CheckId) AS AvgCheckResult
FROM Result
i get this result
+-------------+---------+---------------------+--------------------+-----------------+----------------+
| CheckListId | CheckId | N_AuditForCheckList | AvgCheckListResult | N_AuditForCheck | AvgCheckResult |
+-------------+---------+---------------------+--------------------+-----------------+----------------+
| 1 | 1 | 2 | 1,67 | 1 | 1 |
| 1 | 2 | 2 | 1,67 | 2 | 2 |
| 1 | 2 | 2 | 1,67 | 2 | 2 |
| 2 | 1 | 1 | 3 | 1 | 1 |
+-------------+---------+---------------------+--------------------+-----------------+----------------+
while in AvgCheckListResult i want 2 because on this checklist i have two results: 1 on first audit and 3 on second audit, while sql calculate avg of the 3 rows
Is there a way to do it without sub-query or joining many query?
p.s.
link to test it:
http://rextester.com/ZFEXOD67600
I didn't find (at moment) how to do without a sub query (but I think you already explored my following solution):
P.S. A +1 for the way you wrote your question (scripts, sample data, etc.)
SELECT *
, SUM(CheckListResult / C3 ) OVER (PARTITION BY CheckListId) / N_AuditForCheckList AS AvgChk3
FROM (
SELECT
CheckListId
, CheckId
, AuditId
, CheckListResult
, (dense_rank() over (PARTITION BY CheckListId order by [AuditId])
+ dense_rank() over (PARTITION BY CheckListId order by [AuditId] desc)
- 1) AS N_AuditForCheckList
, AVG(CheckListResult) OVER(PARTITION BY CheckListId) AS AvgCheckListResult
, AVG(CheckListResult) OVER(PARTITION BY CheckListId,AuditId) AS AvgCheckListResult2
, COUNT(*) OVER (PARTITION BY CheckListId, AuditId) AS C3
, COUNT(AuditId) OVER (PARTITION BY CheckListId, CheckId) AS N_AuditForCheck
, AVG(CheckResult) OVER(PARTITION BY CheckListId, CheckId) AS AvgCheckResult
FROM Result) A
Output:
+-------------+---------+---------+-----------------+---------------------+--------------------+---------------------+----+-----------------+----------------+---------+
| CheckListId | CheckId | AuditId | CheckListResult | N_AuditForCheckList | AvgCheckListResult | AvgCheckListResult2 | C3 | N_AuditForCheck | AvgCheckResult | AvgChk3 |
+-------------+---------+---------+-----------------+---------------------+--------------------+---------------------+----+-----------------+----------------+---------+
| 1 | 1 | 1 | 1 | 2 | 1,66666666666667 | 1 | 2 | 1 | 1 | 2 |
| 1 | 2 | 1 | 1 | 2 | 1,66666666666667 | 1 | 2 | 2 | 2 | 2 |
| 1 | 2 | 2 | 3 | 2 | 1,66666666666667 | 3 | 1 | 2 | 2 | 2 |
| 2 | 1 | 1 | 3 | 1 | 3 | 3 | 1 | 1 | 1 | 3 |
+-------------+---------+---------+-----------------+---------------------+--------------------+---------------------+----+-----------------+----------------+---------+
maybe i found a solution with nested query:
SELECT *
,(SELECT AVG(T.CheckListResult)
FROM
(SELECT DISTINCT AuditId, CheckListId, CheckListResult FROM Result) as T
WHERE T.CheckListId = Base.CheckListId
) AS AvgCheckListResult
,(SELECT COUNT(T.CheckListResult)
FROM
(SELECT DISTINCT AuditId, CheckListId, CheckListResult FROM Result) as T
WHERE T.CheckListId = Base.CheckListId
) AS N_AuditForCheckList
,(SELECT AVG(T.CheckResult)
FROM
(SELECT DISTINCT AuditId, CheckId, CheckResult FROM Result) as T
WHERE T.CheckId = Base.CheckId
) AS AvgCheckResult
FROM Result AS Base
result is correct but not sure about performance

No rowid or key need most recent row

I am trying my hardest to get a list of the most recent rows by date in a DB2 file. The file has no unique id, so I am trying to get the entries by matching a set of columns. I need DESCGA most importantly as that changes often. When it does they keep another row for historical reasons.
SELECT B.COGA, B.COMSUBGA, B.ACCTGA, B.PRFXGA, B.DESCGA
FROM mylib.myfile B
WHERE
(
SELECT COUNT(*)
FROM
(
SELECT A.COGA,A.COMSUBGA,A.ACCTGA,A.PRFXGA,MAX(A.DATEGA) AS EDATE
FROM mylib.myfile A
GROUP BY A.COGA, A.COMSUBGA, A.ACCTGA, A.PRFXGA
) T
WHERE
(B.ACCTGA = T.ACCTGA AND
B.COGA = T.COGA AND
B.COMSUBGA = T.COMSUBGA AND
B.PRFXGA = T.PRFXGA AND
B.DATEGA = T.EDATE)
) > 1
This is what I am trying and so far I get 0 results.
If I remove
B.ACCTGA = T.ACCTGA AND
It will return results (of course wrong).
I am using ODBC in VS 2013 to structure this query.
I have a table with the following
| a | b | descri | date |
-----------------------------
| 1 | 0 | string | 20140102 |
| 2 | 1 | string | 20140103 |
| 1 | 1 | string | 20140101 |
| 1 | 1 | string | 20150101 |
| 1 | 0 | string | 20150102 |
| 2 | 1 | string | 20150103 |
| 1 | 1 | string | 20150103 |
and i need
| 1 | 0 | string | 20150102 |
| 2 | 1 | string | 20150103 |
| 1 | 1 | string | 20150103 |
You can use row_number():
select t.*
from (select t.*,
row_number() over (partition by a, b order by date desc) as seqnum
from mylib.myfile t
) t
where seqnum = 1;

ASP.NET Join duplicate results into one and sum other fields

Currently I have the following table in database dbo.test :
agentid | serv | func | com |
--------+------+------+-----|
ampg | 1 | 0 | 1 |
jrep | 0 | 0 | 1 |
ampg | 1 | 1 | 0 |
jrep | 1 | 0 | 1 |
Desired result:
agentid | serv | func | com |
--------+------+------+-----|
ampg | 2 | 1 | 1 |
jrep | 1 | 0 | 2 |
So it recognizes same agent id and combines into one row summing up the values of each other column. I will then present it in gridview in visual. Is it possible?
Thank you
Try this:
select agentid ,sum(serv) as [serv], sum(func) as [func], sum(com) as [com]
from tablename
group by agentid
SQL Group By:
http://www.w3schools.com/sql/sql_groupby.asp
select
agentid,
sum(serv) [sum_serv],
sum(func) [sum_func],
sum(com) [sum_com]
from [table]
group by agentid