how can i combine 2 tables and including if clause into one column - sql

I am pretty new in using SQL and trying to combine 2 tables within APEX ( interactive grid), based on the salary and rate the information to be taken from table X ( which i managed), but i need within the same SQL statement based on the information from column Type, to bring within column percentage if clauses to create the information.
and also within the same SQL statement to have the total which would be (ratehourspercentage).
but it seems i just cant manager to combine so many codes into one correctly, i have tried different ways based on what i have found examples all over, but it seems it will just not work for some reason.
select
Overtime.ID,
OVERTIME.EMPLOYEE_NUMBER,
OVERTIME.EMPLOYEE_FULL_NAME,
OVERTIME."DATE",
OVERTIME.TYPE,
OVERTIME.HOURS,
EMPLOYEES.RATE,
EMPLOYEES.SALARY,
OVERTIME.PERCENTAGE (CASE
WHEN TYPE = "On Call " THEN "70%"
WHEN TYPE = "On Call PH" THEN "100%"
ELSE "150%"
END),
(Rate*hours*percentage) as total,
OVERTIME.CREATED,
OVERTIME.CREATED_BY
from OVERTIME
LEFT OUTER JOIN EMPLOYEES
ON OVERTIME.EMPLOYEE_NUMBER = EMPLOYEES.EMPLOYEE_NUMBER
group by Employee_Number
select
Overtime.ID,
OVERTIME.EMPLOYEE_NUMBER,
OVERTIME.EMPLOYEE_FULL_NAME,
OVERTIME."DATE",
OVERTIME.TYPE,
OVERTIME.HOURS,
EMPLOYEES.RATE,
EMPLOYEES.SALARY,
OVERTIME.PERCENTAGE,
(Rate*hours*percentage) as total,
OVERTIME.CREATED,
OVERTIME.CREATED_BY
from OVERTIME
LEFT OUTER JOIN EMPLOYEES
ON OVERTIME.EMPLOYEE_NUMBER = EMPLOYEES.EMPLOYEE_NUMBER
WHERE OVERTIME.TYPE LIKE
(CASE
WHEN TYPE = "On Call " THEN "70%"
WHEN TYPE = "On Call PH" THEN "100%"
ELSE "150%"
END);
group by Employee_number
The table for Overtime has the below:
ID Number primary Key
Employee_number vchar2
employee_full_name vchar2
date date
type vchar2
hours
salary number
rate number
percentage vachar2
total number
created timestamp
created_by vchar2
for the Employees table
ID number primary key
Employee_number vchar2
employee_full_name vchar2
salary number
rate number
i need to have the percentage information to reflect within the percentage column which i presume should be with if clause

You could calculate the total within the select statement using an SQL CASE statement.
Not sure that is the correct way to calculate the Total Pay - as you will want to Add the Basic Hourly rate to the % rate, but you can change that.
select
Overtime.ID,
OVERTIME.EMPLOYEE_NUMBER,
OVERTIME.EMPLOYEE_FULL_NAME,
OVERTIME."DATE",
OVERTIME.TYPE,
OVERTIME.HOURS,
EMPLOYEES.RATE,
EMPLOYEES.SALARY
,[Percentage] = CASE WHEN [Type] ='On Call ' THEN '70%'
WHEN [Type] = 'On Call PH' THEN '100%'
ELSE '150%'
END
,Total = CASE WHEN [Type] = 'On Call ' THEN (EMPLOYEES.RATE * OVERTIME.HOURS * 0.7)
WHEN [TYPE] = 'On Call PH THEN' THEN (EMPLOYEES.RATE * OVERTIME.HOURS)
ELSE (EMPLOYEES.RATE * OVERTIME.HOURS * 1.5)
END
,OVERTIME.CREATED
,OVERTIME.CREATED_BY
from OVERTIME LEFT OUTER JOIN EMPLOYEES ON OVERTIME.EMPLOYEE_NUMBER = EMPLOYEES.EMPLOYEE_NUMBER
group by Employee_Number

Related

SQL query to return average of results using JOIN and GROUP BY

I have a simple manufacturing job card system that track parts and labor for an assigned job.
It consists of a JobHeader table that holds the Job Card number (JobHeader.JobNo), ID of the part being manufactured (JobHeader.RegNo) and quantity to be manufactured (JobHeader.RegNo).
There is a child table (JobLabour) that tracks all the times that have been worked on the job (JobLabour.WorkedTime)
I'm looking for a query that will return the average time taken to produce a part accross the last 5 job cards for that particular part.
The following query
SELECT TOP 5 JobHeader.RegNo, JobHeader.BOMQty, sum(JobLabour.WorkedTime) AS TotalTime FROM JobHeader INNER JOIN JobLabour ON JobHeader.JobNo=JobLabour.JobNo
WHERE JobHeader.RegNo='RM-BRU-0134'
GROUP BY JobHeader.BOMQty, JobHeader.JobNo, JobHeader.RegNo
will return this:
But what I'm looking for is a query that will return the average BOMQty and average totalTime. Something like this:
Is there a way to do this?
Your question explicitly mentions the "last five" but does not specify how that is determined. Presumably, you have some sort of date/time column in the data that defines this.
In SQL Server, you can use apply:
select jh.*, jl.*
from jobheader jh outer apply
(select top (5) avg(BOMQty) as avg_BOMQty, avg(totalTime) as avg_totalTime
from (select top (5) jl.*
from joblabour jl
where jl.regno = jh.regno
order by jl.<some datetime> -- however you determine the last five
) jl
) jl;
You can add a where clause to the outer query to filter on one or more particular jobs.
If I understand you correctly this will do the work
this will work for 1 RegNo='RM-BRU-0134' at a time
with topFive as (
SELECT TOP 5 JobHeader.RegNo, JobHeader.BOMQty, sum(JobLabour.WorkedTime) AS TotalTime
FROM JobHeader
INNER JOIN JobLabour ON JobHeader.JobNo = JobLabour.JobNo
WHERE JobHeader.RegNo = 'RM-BRU-0134'
GROUP BY JobHeader.BOMQty, JobHeader.JobNo, JobHeader.RegNo
)
select RegNo, avg(BOMQty) as BOMQty, avg(TotalTime) as TotalTime
from topFive
group by RegNo

How to calculate Total transactions amount column with input / output type?

I have two tables : (transactions and Accounts) their columns are as shown in the picture bellow:
the Accounts table is simple just two columns ID and account name.
The important columns in the Transactions table are Amount and type, the type indicates whether the transaction is an input to the account or an output.
I want to find the current total amount (input - output) for each account with SQL.
this what I have tried but I couldn't go further:
select c.TRS_AC_ID, CompAccount, sum(Amount), Type from Accounts c
INNER JOIN Transactions t on c.TRS_AC_ID = t.TRS_AC_ID GROUP by CompAccount, Type
Instead of grouping by the type, you could use a case expression to return "input" transactions as is and "output" transactions as negative numbers:
SELECT c.TRS_AC_ID, CompAccount, SUM(CASE type WHEN 'O' THEN -1 * amount ELSE amount END)
FROM Accounts c
JOIN Transactions t on c.TRS_AC_ID = t.TRS_AC_ID
GROUP BY c.TRS_AC_ID, CompAccount
you can use the following SQL to get the result of input-output, however, if you need individual results then you can use either sub-query as well.
select
(select sum(amount) as input from transaction
where trs_ac_id = '1' and type_io = 'I'))
-
(seelect sum(amount) as output from transaction
where trs_ac_id = '2' and type_io = 'O')) as current_tot_amt
from dual;

Calculated column syntax when using a group by function Teradata

I'm trying to include a column calculated as a % of OTYPE.
IE
Order type | Status | volume of orders at each status | % of all orders at this status
SELECT
T.OTYPE,
STATUS_CD,
COUNT(STATUS_CD) AS STATVOL,
(STATVOL / COUNT(ROW_ID)) * 100
FROM Database.S_ORDER O
LEFT JOIN /* Finding definitions for status codes & attaching */
(
SELECT
ROW_ID AS TYPEJOIN,
"NAME" AS OTYPE
FROM database.S_ORDER_TYPE
) T
ON T.TYPEJOIN = ORDER_TYPE_ID
GROUP BY (T.OTYPE, STATUS_CD)
/*Excludes pending and pending online orders */
WHERE CAST(CREATED AS DATE) = '2018/09/21' AND STATUS_CD <> 'Pending'
AND STATUS_CD <> 'Pending-Online'
ORDER BY T.OTYPE, STATUS_CD DESC
OTYPE STATUS_CD STATVOL TOTALPERC
Add New Service Provisioning 2,740 100
Add New Service In-transit 13 100
Add New Service Error - Provisioning 568 100
Add New Service Error - Integration 1 100
Add New Service Complete 14,387 100
Current output just puts 100 at every line, need it to be a % of total orders
Could anyone help out a Teradata & SQL student?
The complication making this difficult is my understanding of the group by and count syntax is tenuous. It took some fiddling to get it displayed as I have it, I'm not sure how to introduce a calculated column within this combo.
Thanks in advance
There are a couple of places the total could be done, but this is the way I would do it. I also cleaned up your other sub query which was not required, and changed the date to a non-ambiguous format (change it back if it cases an issue in Teradata)
SELECT
T."NAME" as OTYPE,
STATUS_CD,
COUNT(STATUS_CD) AS STATVOL,
COUNT(STATUS_CD)*100/TotalVol as Pct
FROM database.S_ORDER O
LEFT JOIN EDWPRDR_VW40_SBLCPY.S_ORDER_TYPE T on T.ROW_ID = ORDER_TYPE_ID
cross join (select count(*) as TotalVol from database.S_ORDER) Tot
GROUP BY T."NAME", STATUS_CD, TotalVol
WHERE CAST(CREATED AS DATE) = '2018-09-21' AND STATUS_CD <> 'Pending' AND STATUS_CD <> 'Pending-Online'
ORDER BY T."NAME", STATUS_CD DESC
A where clause comes before a group by clause, so the query
shown in the question isn't valid.
Always prefix every column reference with the relevant table alias, below I have assumed that where you did not use the alias that it belongs to the orders table.
You probably do not need a subquery for this left join. While there are times when a subquery is needed or good for performance, this does not appear to be the case here.
Most modern SQL compliant databases provide "window functions", and Teradata does do this. They are extremely useful, and here when you combine count() with an over clause you can get the total of all rows without needing another subquery or join.
Because there is neither sample data nor expected result provided with the question I do not actually know which numbers you really need for your percentage calculation. Instead I have opted to show you different ways to count so that you can choose the right ones. I suspect you are getting 100 for each row because the count(status_cd) is equal to the count(row_id). You need to count status_cd differently to how you count row_id. nb: The count() function increases by 1 for every non-null value
I changed the way your date filter is applied. It is not efficient to change data on every row to suit constants in a where clause. Leave the data untouched and alter the way you apply the filter to suit the data, this is almost always more efficient (search sargable)
SELECT
t.OTYPE
, o.STATUS_CD
, COUNT(o.STATUS_CD) count_status
, COUNT(t.ROW_ID count_row_id
, count(t.row_id) over() count_row_id_over
FROM dbo.S_ORDER o
LEFT JOIN dbo.S_ORDER_TYPE t ON t.TYPEJOIN = o.ORDER_TYPE_ID
/*Excludes pending and pending online orders */
WHERE o.CREATED >= '2018-09-21' AND o.CREATED < '2018-09-22'
AND o.STATUS_CD <> 'Pending'
AND o.STATUS_CD <> 'Pending-Online'
GROUP BY
t.OTYPE
, o.STATUS_CD
ORDER BY
t.OTYPE
, o.STATUS_CD DESC
As #TomC already noted, there's no need for the join to a Derived Table. The simplest way to get the percentage is based on a Group Sum. I also changed the date to an Standard SQL Date Literal and moved the where before group by.
SELECT
t."NAME",
o.STATUS_CD,
Count(o.STATUS_CD) AS STATVOL,
-- rule of thumb: multiply first then divide, otherwise you will get unexpected results
-- (Teradata rounds after each calculation)
100.00 * STATVOL / Sum(STATVOL) Over ()
FROM database.S_ORDER AS O
/* Finding definitions for status codes & attaching */
LEFT JOIN database.S_ORDER_TYPE AS t
ON t.ROW_ID = o.ORDER_TYPE_ID
/*Excludes pending and pending online orders */
-- if o.CREATED is a Timestamp there's no need to apply the CAST
WHERE Cast(o.CREATED AS DATE) = DATE '2018-09-21'
AND o.STATUS_CD NOT IN ('Pending', 'Pending-Online')
GROUP BY (T.OTYPE, o.STATUS_CD)
ORDER BY T.OTYPE, o.STATUS_CD DESC
Btw, you probably don't need an Outer Join, Inner should return the same result.

How to using subquery values in arithmetic operations

My manager wants to see what is total values of our suppliers shipments, and what is the total values of their invoices recorded. So he can see the differencies and want from suppliers to unsended invoices.
Here is my code.
It is working on accounting table and shipment detail table.
fis_meblag0 is always little from zero because it is 320 account so I mutiply it -1 for get real value.
sth_tutar is value of shipment, sth_vergi is VAT and so the sum of them is equal to sum of total with VAT.
Now the hard part.
Manager wants to diference between them in a other column and also sort the valuez z to a.
I know I can reuse same subselect for the getting totals but I want to know that can I achieve this without using the same subquery again.
I mean in first subselect I have the total, in last column I only need just the total, can I use total without compute it again?
Regards
select
ch.cari_kod as Carikod,
ch.cari_unvan1 as Unvani,
(select (sum(mf.fis_meblag0) * -1)
from dbo.MUHASEBE_FISLERI mf
where (mf.fis_tarih > '20141231' and mf.fis_tarih < '20150201')
and mf.fis_hesap_kod = ch.cari_kod
and mf.fis_meblag0 < 0) as mtoplam,
(Select sum (sth.sth_tutar + sth.sth_vergi)
from dbo.STOK_HAREKETLERI sth
where (sth.sth_tarih > '20141231' and sth.sth_tarih < '20150201')
and sth.sth_cari_kodu = ch.cari_kod
and sth.sth_normal_iade = 0
and sth.sth_tip = 0) as stoplam
from
dbo.CARI_HESAPLAR ch
where
ch.cari_kod like '320%'
try this query:
select Carikod, Unvani, mtoplam, stoplam, mtoplam - stoplam as Grand_total
from
(
-- your full query here
) T

Performance issue in retrieving multiple output of the same column with different values from a single table

is there anyway to get the following results from query without joining the same table three times (or) without reading the same "wordlocation" table three times (or more if there are more words)? If there are three or more words, it takes about over a minute for the results to be returned.
Currently "wordlocation" table has three rows being ("bookid","wordid","location") and it currently has 917802 rows.
What I am trying to do is
retrieve the "bookid" that contains all the words specified in the query by "wordid".
sum word count of all words (from the query) from each book
minimum values of each word location, e.g. (min(w0.location), min (w1.location)
I have tried commenting out count(w0.wordid) and min(location) calculations to see whether they are affecting the performance but this is not the case. Joining the same table multiple time was the case.
(this is the same code as the above image)
select
w0.bookid,
count(w0.wordid) as wcount,
abs(min(w0.location) + min(w1.location) + min(w2.location)) as wordlocation,
(abs(min(w0.location) - min(w1.location)) + abs(min(w1.location) - min(w2.location))) as distance
from
wordlocation as w0
inner join
wordlocation as w1 on w0.bookid = w1.bookid
join
wordlocation as w2 on w1.bookid = w2.bookid
where
w0.wordid =3
and
w1.wordid =52
and
w2.wordid =42
group by w0.bookid
order by wcount desc;
This is the result that I am looking for, and which I got from running the above query, but it takes too long if I specify more than 3 words, e.g. (w0 = 3, w1 = 52 , w2 = 42, w3 = 71)
Try this query
SELECT bookid,
ABS(L3+L52+L42) as wordlocation,
ABS(L3-L52)+ABS(L52-L42) as distance
FROM
(SELECT bookid, wordid, CASE WHEN wordid=3 THEN min(location) ELSE 0 END L3,
CASE WHEN wordid=52 THEN min(location) ELSE 0 END L52,
CASE WHEN wordid=42 THEN min(location) ELSE 0 END L42
FROM wordlocation WL
WHERE wordid in (3,52,42)
GROUP BY bookid, wordid) T
GROUP BY bookid
You may also need to create index on wordid