sum of two field in two table - sql

I have four tables in the database as follows:
tblInvoice:
invcid,customerid,invoicedate
tblInvcDetail:
ID,invcid,item,itemprice,itemquantity
tblPay:
payid,invcid,paydate
tblPayDetail:
payid,amount
I need to create a list of invoiceid, invoicedate, (sum of itemprice*itemquantity), (sum of amount) where userid is given.
I tried this query:
SELECT tblinvoice.invcid,
tblinvoice.invcdate,
Sum(tblinvcdetail.itemprice * tblinvcdetail.itemquantity) AS SumOfInvoice,
Sum(tblpaydetail.amount) AS SumOfAmount
FROM ((tblinvoice
LEFT JOIN tblpay
ON tblinvoice.invcid = tblpay.invcid)
LEFT JOIN tblinvcdetail
ON tblinvoice.invcid = tblinvcdetail.invcid)
LEFT JOIN tblpaydetail
ON tblpay.payid = tblpaydetail.payid
GROUP BY tblinvoice.invcid,
tblinvoice.invcdate;
But the result is not quite correct
Please help me.
Thanks a lot.
Sample data:
tblInvoice:
invcid customerid invcdate |invcsum(manualy calculated)
18 8 6/30/2012 |$140,000
39 8 7/12/2012 |$170,000
40 8 7/12/2012 |$80,000
43 8 7/14/2012 |$80,000
44 8 7/14/2012 |$80,000
45 8 7/15/2012 |$700,000
46 8 7/17/2012 |$180,000
tblInvcDetail:
ID invccid itemname itemprice itemquantity
19 18 X $70,000 2
92 39 Y $80,000 1
93 39 Z $90,000 1
94 40 Y $80,000 1
97 43 Y $80,000 1
98 44 Y $80,000 1
99 45 W $700,000 1
100 46 Y $80,000 1
101 46 U $100,000 1
tblPay:
payid invcid paydate |AmountSUM(Manually Calculated)
35 18 7/11/2012 |$120,000
40 18 7/12/2012 |$147,000
41 40 7/12/2012 |$84,000
44 44 7/14/2012 |$84,000
46 45 7/15/2012 |$700,000
tblPayDetail:
payid amount
35 $100,000
35 $20,000
40 $147,000
41 $84,000
44 $84,000
46 $700,000
And finally the query result is:
invcid invcdate SumOfInvoice SumOfAmount
18 6/30/2012 $420,000.00 $267,000.00
39 7/12/2012 $170,000.00
40 7/12/2012 $80,000.00 $84,000.00
43 7/14/2012 $80,000.00
44 7/14/2012 $80,000.00 $84,000.00
45 7/15/2012 $700,000.00 $700,000.00
46 7/17/2012 $180,000.00
You can see that the calculation is wrong in the first row (SumOfInvoice column)
and the rest is correct!

How about:
SELECT a.invcid,
a.invcdate,
a.sumofinvoice,
b.sumofamount
FROM (SELECT ti.invcid,
ti.invcdate,
SUM(td.itemprice * td.itemquantity) AS SumOfInvoice
FROM tblinvoice AS ti
LEFT JOIN tblinvcdetail AS td
ON ti.invcid = td.invcid
GROUP BY ti.invcid,
ti.invcdate) a
LEFT JOIN (SELECT tp.invcid,
SUM(tpd.amount) AS SumOfAmount
FROM tblpay AS tp
LEFT JOIN tblpaydetail AS tpd
ON tp.payid = tpd.payid
GROUP BY tp.invcid) b
ON a.invcid = b.invcid

Related

Selecting rows where values in one column are different, other column(s) values are similar and values of Date columns are correct

Suppose I have the following columns:
ID,Code,DST,Short_text,Long_text,Date_from,Date_until
Here is the dataset:
ID Code DST Short_text Long_text Date_From Date_Until
1 B 01 B 1 Bez1 Bezirk1 29.10.1999 13.01.2020
1 B 01 B 1 Bez1 Bezirk1 14.01.2020 31.12.9999
2 B 02 B 2 Bez2 Bezirk2 29.10.1999 13.01.2020
3 B 03 B 3 Bez3 Bezirk3 14.01.2020 31.12.9999
4 B 04 B 4 Bez4 Bezirk4 29.10.1999 13.01.2020
4 B 04 B 4 Bez4 Bezirk4 14.01.2020 31.12.9999
97 M 51 M 52 MA 51 Sport 29.10.1999 13.01.2020
96 M 51 M 51 MA 51 Sport 14.01.2020 31.12.9999
98 M 55 M 53 MA 53 Dance 29.10.1999 13.01.2020
99 M 55 M 54 MA 54 Skating 14.01.2020 31.12.9999
100 M 56 M 59 MA 57 Football 29.10.1999 13.01.2020
101 M 56 M 56 MA 56 Tennis 29.10.1999 31.12.9999
I want to select rows, such that they have different ID AND (they have similar Code OR SImilar Short_text OR simmlar long_text) AND Correct Date_from - Date_Until.
Definition of correct Date_from - Date_Until:
1.Date_ from < Date_Until
2.Both fields are not Null
3. WHEN PREV_DATE_UNTIL = DATE_FROM - 1 OR PREV_DATE_UNTIL is null THEN 'OK'(PREV_DATE_UNTIL using lag operator)
4. WHEN NEXT_DATE_FROM = DATE_UNTIL + 1 OR NEXT_DATE_FROM is null THEN 'OK'(NEXT_DATE_FROM using lead operator)
Not correct:
WHEN WHEN NEXT_DATE_FROM > DATE_UNTIL + 1 THEN 'Gaps in Dates'
WHEN WHEN NEXT_DATE_FROM < DATE_UNTIL + 1 THEN 'Overlapping dates'
Basically what I mean, that historization of the data must be correct(no overlapping)
At the end I want to select the following rows:
97 M 51 M 52 MA 51 Sport 29.10.1999 13.01.2020
96 M 51 M 51 MA 51 Sport 14.01.2020 31.12.9999
Because they have different ID and similar Code or short_text or long_text and dates are correct according to the definition
And
98 M 55 M 53 MA 53 Dance 29.10.1999 13.01.2020
99 M 55 M 54 MA 54 Skating 14.01.2020 31.12.9999
Because they have different ID and similar Code and dates are correct according to the definition
Rows:
100 M 56 M 59 MA 57 Football 29.10.1999 13.01.2020
101 M 56 M 56 MA 56 Tennis 29.10.1999 31.12.9999
Should NOT be selected, because they have different ID and similar Code BUT they have incorrect Dates(they are overlapping).
This will be something like that:
with t as (
select row_number() over (order by date_from, date_until) rn,
id, code, dst, short_text, long_text, date_from,
nullif(date_until, date '9999-12-31') date_until
from data)
select rna, rnb, description, t.*
from t
join (
select a.rn rna, b.rn rnb,
case when b.date_from = a.date_until + 1 then 'OK'
when b.date_from > a.date_until + 1 then 'gaps'
when b.date_from < a.date_until + 1 then 'overlapping'
end description
from t a
join t b on a.id <> b.id and a.rn < b.rn
and (a.code = b.code or a.short_text = b.short_text
or a.long_text = b.long_text)) pairs
on rn in (rna, rnb)
result is:
RNA RNB DESCRIPTION RN ID CODE DST SHORT_TEXT LONG_TEXT DATE_FROM DATE_UNTIL
------ ------ ----------- ----- ---------- ---- ---- ---------- --------- ----------- -----------
1 7 overlapping 1 100 M 56 M 59 MA 57 Football 1999-10-29 2020-01-13
1 7 overlapping 7 101 M 56 M 56 MA 56 Tennis 1999-10-29
3 8 OK 3 98 M 55 M 53 MA 53 Dance 1999-10-29 2020-01-13
3 8 OK 8 99 M 55 M 54 MA 54 Skating 2020-01-14
6 9 OK 6 97 M 51 M 52 MA 51 Sport 1999-10-29 2020-01-13
6 9 OK 9 96 M 51 M 51 MA 51 Sport 2020-01-14
dbfiddle
I numbered rows, self joined such data and dressed your logic in case when syntax. I tested on your examples, in case of any mistakes please provide dbfiddle if possible.

Calculating Average based on Month and ID in SQL

I have a sample table like below and would like to do average based on MONTH of the DATE and ID. Is there any way I could do this in SQL.
Table:Input
DATE ID VOLUME
20080630 A 45
20080628 A 23
20080629 A 34
20080627 A 33
20080730 A 45
20080728 A 12
20080730 A 34
20080724 A 56
20080430 A 34
20080428 A 23
20080630 B 12
20080628 B 45
20080629 B 67
20080627 B 78
20080730 B 45
20080728 B 12
20080730 B 34
20080724 B 56
20080430 B 2
20080428 B 34
Table:Output
DATE ID VOLUME AVERAGE
20080630 A 45 33.75
20080628 A 23 33.75
20080629 A 34 33.75
20080627 A 33 33.75
20080730 A 45 36.75
20080728 A 12 36.75
20080730 A 34 36.75
20080724 A 56 36.75
20080430 A 34 28.5
20080428 A 23 28.5
20080630 B 12 50.5
20080628 B 45 50.5
20080629 B 67 50.5
20080627 B 78 50.5
20080730 B 45 36.75
20080728 B 12 36.75
20080730 B 34 36.75
20080724 B 56 36.75
20080430 B 2 18
20080428 B 34 18
You could try this Query:
select DATE_FORMAT(date,'%Y%m'), id, avg(volume) from xxx1
group by DATE_FORMAT(date,'%Y%m'), ID;
or
select DATE_FORMAT(date,'%m'), id, avg(volume) from xxx1
group by DATE_FORMAT(date,'%m'), ID
Explanation:
DATE_FORMAT(date,'%Y%m') extracts the month and year from the date. Whereas DATE_FORMAT(date,'%m') extracts only the month. (I was not quite sure, if you want the month without the year).
Basically you extract the month and then group by it together with the id and calculate the average of the volume for these groups.
This is a Standard SQL answer, as you didn't tag your DBMS:
AVG(VOLUME)
OVER (PARTITION BY EXTRACT(YEAR FROM datecolumn)
,EXTRACT(MONTH FROM datecolumn))
If you are using the mssql server then so
select t1.*, t2.AVG
from TABLE1 t1
join
(
SELECT avg(volume) as AVG, MONTH(date) as DATE
FROM TABLE1
GROUP BY MONTH(date), ID
) t2 on MONTH(t1.DATE) = t2.DATE
The output will match the required. The query will select all columns from source table and will add GROUP BY one column.

SQL Server Obtain Pairs of records

I am trying to obtain "pairs" of records and I just cant figure out.
Here is what I have:
Id TruckId LocationId MaterialMode
145223 1198 19 43
145224 1199 19 43
145225 1200 19 43
145226 1198 20 43
145227 1199 20 43
145228 1200 20 43
145229 1199 21 46
145230 1198 21 46
145231 1200 21 46
145232 1198 22 46
145233 1199 22 46
145234 1200 22 46
145235 1198 19 43
145236 1199 19 43
145237 1200 19 43
145238 1198 20 43
145239 1199 20 43
145240 1200 20 43
145241 1199 21 46
145242 1198 21 46
145243 1200 21 46
145244 1198 22 46
145245 1199 22 46
145246 1200 22 46
I need to get the following:
Id A Id B
145223 145226
145224 145227
145225 145228
145229 145233
145230 145232
145231 145234
145235 145238
145236 145239
145237 145240
145241 145245
145242 145244
145243 145246
Basically matching a TruckId between 2 locations under the same material mode
I have tried:
SELECT
Id AS IdA,
Lead(Id, 1, NULL) OVER(PARTITION BY TruckId, MaterialMode ORDER BY Date) AS IdB
FROM T
This produces:
Id A Id B
145223 145226
145224 145227
145225 145228
*145226 145235
*145227 145236
*145228 145237
145229 145233
145230 145232
145231 145234
*145232 145242
*145233 145241
*145234 145243
145235 145238
145236 145239
145237 145240
145241 145245
145242 145244
145243 145246
Records with the * I don't want them. If a pair is matched then that record should not be part of "another match"
I believe I understand your problem and below is a solution.
Explanation: I sorted the data rows into start and end points sets like in gap and islands problems and then joined a start id with end id for same material mode and truck.
; with separationSet as
(
select
*,
dense_rank()
over(
partition by materialmode,truckid
order by locationid asc
) as r
from T
)
, scoredSet as
(
select
*,
row_number()
over(
partition by materialmode,truckid,r
order by id
) as r2
from separationSet
)
, startToEndPairs as
(
select
S.id as StartId,
E.id as EndId
from scoredSet S
join scoredSet E
on S.r=1 and E.r=2
and S.r2=E.r2
and S.TruckId=E.TruckId
and S.materialmode=E.materialmode
)
select
*
from starttoEndPairs
order by StartId asc
See working demo

how to order student rank on the basis of obtain marks on different subject in sql

Here is our table
name math physics chemistry hindi english
pk 85 65 45 54 40
ashis 87 44 87 78 74
rohit 77 47 68 63 59
mayank 91 81 78 47 84
komal 47 51 73 61 55
we want to result show as (summing the grades essentially)
rank name total
1 mayank 381
2 ashis 370
3 rohit 314
4 pk 289
5 komal 287
SET #rank=0;
SELECT #rank:=#rank+1 AS rank,name,(math+physics+chemistry+hindi+english) as total
FROM tablename ORDER BY total DESC
this will produce your desired result as
rank | name | total
--------------------
1 | mayank | 381
2 | ashis | 370
for more details take a look mysql ranking results
Try this
SELECT #curRank := #curRank + 1 AS rank, name, (math + physics + chemistry + hindi + history) AS total FROM table, (SELECT #curRank := 0) r ORDER BY total DESC;
This will sum all the fields and sort them by descending order and add a rank.
By doing SELECT #curRank := 0 you can keep it all in one SQL statement without having to do a SET first.

Oracle - Group By Creating Duplicate Rows

I have a query that looks like this:
select nvl(trim(a.code), 'Blanks') as Ward, count(b.apcasekey) as UNSP, count(c.apcasekey) as GRAPH,
count(d.apcasekey) as "ANI/PIG",
(count(b.apcasekey) + count(c.apcasekey) + count(d.apcasekey)) as "TOTAL ACTIVE",
count(a.apcasekey) as "TOTAL OPEN" from (etc...)
group by a.code
order by Ward
The reason I have nvl(trim(a.code), 'Blanks') as Ward is that sometimes a.code is a blank string, sometimes it's a null.
The problem is that when I use the Group By statement, I can't use Ward or I get the error
Ward: Invalid Identifier
I can only use a.code so I get 2 rows for 'Blanks', as per below
1 Blanks 7 0 0 7 7
2 Blanks 23 1 1 25 30
3 W01 75 4 0 79 91
4 W02 62 1 0 63 72
5 W03 140 2 0 142 162
6 W04 6 1 0 7 7
7 W05 46 0 1 47 48
8 W06 322 46 1 369 425
9 W07 91 0 1 92 108
10 W08 93 2 0 95 104
11 W09 28 1 0 29 30
12 W10 25 0 0 25 28
What I need, is for the row with 'Blanks' to combined into 1 row. Little help?
Thanks.
You can not use the alias in the GROUP BY, but you can use the expression that builds the value:
GROUP BY nvl(trim(a.code), 'Blanks')