computation within same table - sql

I have a table called factprojection which has the columns as shown in the image.
I want to multiply the 'value' column which have 'Total Lines & RSV Required'in the 'Measures' column with the 'value' column which have 'Line Average' in the 'Measures' column joining it by crew type. Should I create a temp table and then perform the multiplication? Could anyone help me with this?

N.B. I'm assuming all CrewType and DateKey values are in both tables, so all answers below use inner joins (any rows not matching on both sides are not returned)
Common Table Expressions (CTEs)
You can define Common Table Expressions that perform queries on the table, and then name those queries. You can then join these 'sub-tables', rather than generating any temporary data:
WITH LineAverage as (
select *
from factprojection
where Measure = 'Line Average'
)
,TotalLines as (
select *
from factprojection
where Measure = 'Total Lines & RSV Required'
)
select
LA.CrewType
,LA.DateKey
,LA.Value*TL.Value as newvalue
from LineAverage LA
inner join
TotalLines TL
ON LA.DateKey = TL.DateKey
and LA.CrewType = TL.CrewType
Self join
An equivalent but less visually obvious approach is a self-join, giving the tables different aliases:
select
LA.CrewType
,LA.DateKey
,LA.Value*TL.Value as newvalue
from factprojection LA,
factprojection TL
where LA.DateKey = TL.DateKey
and LA.CrewType = TL.CrewType
and LA.Measure = 'Line Average'
and TL.Measure = 'Total Lines & RSV Required'
Notice the use of restrictions on the Measure values alongside the join conditions in the WHERE clause. Although this query is marginally shorter to write it loses some readability over the CTE approach.
Here I've also used the comma form of an INNER JOIN, where the ON clause is replaced by placing the join conditions in the WHERE clause.

Related

Replace row with Column Data in Sql Server

I have a table with some data and I was trying to Replace the Column with Row.
SELECT Handset_UID, [IMEI_NO_1] AS [IMEI #1],[IMEI_NO_2] AS [IMEI #2],
Isnull(Convert(varchar,Mfg_Date,106),'Not Found') as [Mfg. Date]
FROM stock.Handset a
join Stock.Model b
on a.Model_ID = b.Model_ID
JOIN Stock.Brand C
ON A.Brand_ID = C.Brand_ID
where a.Handset_UID = 'GFI13508637275434'
The above Query gives me the result in one single row data.
But I want the Result in below format
I have tried the Pivot Operator using Derived Column but got confused during implementation.
Please help to get the correct query.
Assuming that you are running SQL Server, as the syntax suggests, you can unpivot with cross apply:
select x.col, x.val
from stock.handset h
inner join stock.model m on h.model_id = m.model_id
inner join stock.brand b on on h.brand_id = b.brand_id
cross apply (values
('handset_uid', handset_uid),
('IMEI #1', imei_no_1),
('IMEI #2', imei_no_2),
('Mfg.Date', convert(varchar, Mfg_Date, 106), 'Not Found')
) x(col, val)
where h.handset_uid = 'gfi13508637275434'
Side notes:
meaningful table aliases make the query easier to read and write
your query has many columns that are not qualified with the alias of the table they belong to, which makes your query rather unclear about the underlying structure; I would strongly recommend that you qualify all columns in the query

How to JOIN on different CONCAT expressions?

I am attempting to Join tables based on a CONCAT expression containing different text criteria.
I have tried a inefficient method that just takes way too long to query.
SELECT
sf.displayId,
-- tw.displayText,
CASE
WHEN tw.DisplayText IN ('N/A', 'NotApplicable', 'Not Applicable')
THEN 'Not Applicable'
ELSE REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(tw.DisplayText,'client','Client'),'approved','Approved'),'rejected','Rejected'),'review','Review'),'Requirement','Requirement'),'open','Open'),'submitted','Submitted'),'complete','Complete'),'incomplete','Incomplete'),'pending','Pending'),'resubmit','Resubmit'),'Awaiting review','Awaiting Review')
END AS AuditStatus
FROM Connect.Data.supplier_form sf
JOIN Connect.Data.translation tw
ON ((CONCAT('workflowStepName' , sf.workflowStatusId) = tw.translationField) OR (CONCAT('workflowStepMessage' , sf.workflowStatusId) = tw.translationField))
AND tw.language = 'en'
WHERE sf.deleted = 0
AND tw.displayText IN ('Awaiting Review','Awaiting review')
ORDER BY sf.displayId
OFFSET 0 ROWS
FETCH NEXT 100 ROWS ONLY;
I want to JOIN Connect.Data.supplier_form sf based on the CONCAT expression in a far more efficient way.
I'm not sure how good the SQL optimizer is in SQL Server, so you may try to flip the order of the join condition to make it easier to use an index. I would do two things:
I would change the JOIN condition to:
JOIN Connect.Data.translation tw
ON tw.language = 'en'
AND tw.translationField in (
CONCAT('workflowStepName' , sf.workflowStatusId),
CONCAT('workflowStepMessage' , sf.workflowStatusId)
)
And I would add the index:
create index ix1 on Connect.Data.translation(language, translationField);
Give it a try and let us know if it improves the performance.

conditional IIF in a JOIN

I have the next data base:
Table Bill:
Table Bill_Details:
And Table Type:
I want a query to show this result:
The query as far goes like this:
SELECT
Bill.Id_Bill,
Type.Id_Type,
Type.Info,
Bill_Details.Deb,
Bill_Details.Cre,
Bill.NIT,
Bill.Date2,
Bill.Comt
FROM Type
RIGHT JOIN (Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill)
ON Type.Id_Type = Bill_Details.Id_Type
ORDER BY Bill.Id_Bill, Type.Id_Type;
With this result:
I'm not sure how to deal or how to include this:
Type.600,
Type."TOTAL",
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) >= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), "" ),
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) <= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), "" )
The previous code is the responsable of include new data in some fields, since all of the other fields will carry the same data of the upper register. I'll apreciate some sugestions to acomplish this.
Here is a revised version of the UNION which you removed from the question. The original query was a good start, but you just did not provide sufficient details about the error or problem you were experiencing. My comments were not meant to have you remove the problem query, only that you needed to provide more details about the error or problem. In the future if you have a UNION, make sure the each query of the UNION works separately. Then you could debug problems easier, one step at a time.
Problems which I corrected in the second query of the UNION:
Removed reference to table [Type] in the query, since it was not part of the FROM clause. Instead, I replaced it with a literal value.
Fixed FROM clause to join both [Bill] and [Bill_Details] tables. You had fields from both tables, so why would you not join on them just like in the first query of the UNION?
Grouped on all fields from table [Bill] referenced in the SELECT clause. You must either group on all fields, or include them in aggregate expressions like Sum() or First(), etc.
Replaced empty strings with Nulls for the False cases on Iif() statements.
SELECT
Bill.Id_Bill, Type.Id_Type, Type.Info,
Bill_Details.Deb,
Bill_Details.Cre,
Bill.NIT, Bill.Date2, Bill.Comt
FROM
Type RIGHT JOIN (Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill)
ON Type.Id_Type = Bill_Details.Id_Type;
UNION
SELECT
Bill.Id_Bill, 600 As Id_Type, "TOTAL" As Info,
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) >= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), Null ) As Deb,
IIF(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre) <= 0, ABS(SUM(Bill_Details.Deb) - Sum(Bill_Details.Cre)), Null ) As Cre,
Bill.NIT, Bill.Date2, Bill.Comt
FROM Bill INNER JOIN Bill_Details
ON Bill.Id_Bill = Bill_Details.Id_Bill
GROUP BY Bill.Id_Bill, Bill.NIT, Bill.Date2, Bill.Comt;

CONCAT value in ON condition of JOIN

I have two tables.
Table: Geonames:
Country (2 character ISO code, e.g. SE)
AdminArea (Char code, e.g. 0330)
Table AdminAreas
AdminCode, (Combination of Coutry and AdminArea, e.g. "SE.0330")
So the ID of the AdminAreas that I want to join the tables on is a combination of columns on the first table. To join it I will need to join the two values from the Geonames table. Something like.
SELECT
geoname.geonameid, geoname.name, geoname.latitude, geoname.longitude,
geoname.country, geoname.admin1, admin_one.admin_id, admin_one.geoname_id
FROM geoname
INNER JOIN admin_one ON admin_one.admin_id = CONCAT(geoname.country, '.', geoname.admin1)
WHERE country='SE' LIMIT 10
Unfortunately, this is not working. It does not seem like i can CONCAT or do string_agg() on a JOIN. How do I get this JOIN working?
Your code is fine. Perhaps one issue is that you have spaces or some other character. I would recommend investigating this using:
SELECT gn.geonameid, gn.name, gn.latitude, gn.longitude,
gn.country, gn.admin1, ao.admin_id, ao.geoname_id
FROM geoname gn LEFT JOIN
admin_one ao
ON ao.admin_id = CONCAT(TRIM(gn.country), '.', TRIM(gn.admin1))
WHERE gn.country = 'SE'
LIMIT 10;
This will return even unmatched results (because of the LEFT JOIN). That might help you investigate the issue.

How do I generate an Oracle SQL statement , where each column would need its own separate query?

I have a query where I need to use separate queries to fill in the individual columns :
It would look Something like this for each column
select PERFORMED_DATE from HHS_UMX_RESP_ACTIVITY where
REG_REQUEST_ID IN ('261507') AND ACTIVITY_RESULT_CODE = 'ASD'
AS "Security"
UNION
select PERFORMED_DATE from HHS_UMX_RESP_ACTIVITY where
REG_REQUEST_ID IN ('261507') AND ACTIVITY_RESULT_CODE = 'OTZ'
AS "Training"
UNION
select PERFORMED_DATE from HHS_UMX_RESP_ACTIVITY where
REG_REQUEST_ID IN ('261507') AND ACTIVITY_RESULT_CODE = 'ARA'
AS "Responsibility"
The only thing changing in each column is the ACTIVITY_RESULT_CODE.
I know that this syntax would not work. Is there a syntax to do this?
My query would grab different data from a specific table, for each different column.
My database output screenshot, which is for this query :
SELECT * FROM HHS_UMX_RESP_ACTIVITY where REG_REQUEST_ID IN ('262050') AND ACTIVITY_RESULT_CODE = 'ASD' AND ROWNUM < 2 :
The user-spreadsheet looks like this :
So columns "Responsibility" / "Supervisor" would each correspond to their own unique value for the column ACTIVITY_RESULT_CODE ( these called "UPA request statuses" - one of SBT, WSP, ASP, WRA, ARA, WTV, ATV ... etc ) :
thanks !
So you want to display information from different rows in the same row of the result set. The standard answer is a join, even if we join the same table:
select
securityRow.REQ_REQUEST_ID,
securityRow.PERFORMED_DATE as securityDate,
trainingRow.PERFORMED_DATE as trainingDate,
responsibilityRow.PERFORMED_DATE as responsibilityDate
from HHS_UMX_RESP_ACTIVITY securityRow
join HHS_UMX_RESP_ACTIVITY trainingRow on trainingRow.REG_REQUEST_ID = securityRow.REG_REQUEST_ID
join HHS_UMX_RESP_ACTIVITY responsibilityRow on responsibilityRow.REQ_REQUEST_ID = securityRow.REG_REQUEST_ID
where securityRow.ACTIVITY_RESULT_CODE = 'ASD'
and trainingRow.ACTIVITY_RESULT_CODE = 'OTZ'
and responsibilityRow.ACTIVITY_RESULT_CODE = 'ARA'
This assumes that there is exactly one row matching for each REQ_REQUEST_ID and ACTIVITY_RESULT_CODE. Otherwise, if there is at most one, you'll want to use outer joins as necessary. If there are several rows, you must restrict the result set to the one you want to use.
You say "For each different column" but there are not different columns. Only different selections on the Activity_result_code.
They syntax you have now, with the exception of the table aliases, would work fine, it's just completely unnecessary. The query you have written could also be written as:
select PERFORMED_DATE
from HHS_UMX_RESP_ACTIVITY
where REG_REQUEST_ID = '261507' AND ACTIVITY_RESULT_CODE IN ('ASD','OTZ','ARA');
GROUP BY PERFORMED_DATE