How to join 100 random rows from table 1 multiple other tables in oracle - sql

I have scrapped my previous question as I did not do a good job explaining. Maybe this will be simpler.
I have the following query.
Select * from comp_eval_hdr, comp_eval_pi_xref, core_pi, comp_eval_dtl
where comp_eval_hdr.START_DATE between TO_DATE('01-JAN-16' , 'DD-MON-YY')
and TO_DATE('12-DEC-17' , 'DD-MON-YY')
and comp_eval_hdr.COMP_EVAL_ID = comp_eval_dtl.COMP_EVAL_ID
and comp_eval_hdr.COMP_EVAL_ID = comp_eval_pi_xref.COMP_EVAL_ID
and core_pi.PI_ID = comp_eval_pi_xref.PI_ID
and core_pi.PROGRAM_CODE = 'PS'
Now if I only want a random 100 rows from the comp_eval_hdr table to join with the other tables how would I go about it? If it makes it easier you can disregard the comp_eval_dtl table.

I think you are pretty much there. You just need subqueries, table aliases, and JOIN conditions:
SELECT . . .
FROM (SELECT a.*
FROM (SELECT a.*
FROM a
WHERE a.START_DATE BEWTWEEN DATE '2016-01-01' AND DATE '2017-12-12'
ORDER BY DBMS_RANDOM.VALUE
) a
WHERE ROWNUM <= 100
) a JOIN
mapping m
ON a.? = m.? JOIN
b
ON m.? = b.?;
The ? is just a placeholder for the join columns.

It's a bit of a stretch to know what you want with the question as written but here's my attempt.
WITH rand_list AS
(SELECT * FROM comp_eval_hdr
WHERE comp_eval_hdr.START_DATE BEWTWEEN TO_DATE('01-JAN-16' , 'DD-MON-YY') AND TO_DATE('12-DEC-17' , 'DD-MON-YY')
ORDER BY DBMS_RANDOM.VALUE)
first_100 AS
(SELECT *
FROM rand_list
WHERE ROWNUM <=100)
SELECT md.col_1, t3.col_a
FROM first_100 md
INNER JOIN
table2 t2 ON md.id_column = t2.fk_comp_eval_hdr_id
INNER JOIN
table3 t3 ON t3.id_column = t2.fk_table3_id
You haven't given any indication how they join or the table names and obviously I haven't run this against any mock tables.
You've got a list of randomised records with RAND_LIST which you could, if you wanted, combine with the FIRST_100 query (your choice).
The main query then just joins that through your mapping table (T2) to your 'multiples' table (T3).

how does table 2 look like?...Let me put one example as person table and order table?
select * from (
select * from person ps , order order where ps.city = 'mumbai' and ps.id = order.purchasedby ) porder where porder.rownum <= 100
I did not tested it but it will look something like this.

Related

Inner Joining table on column issue

Below is my query, for some reason this keeps running and doesn't return anything. I wanted to inner join both tables and add condition booking_value=1 which happens to be in the table that I am joining. I want all the records to show up that has the same rental date as the second table but where booking _value= 1.
select a.timestamp , SUM(DEMAND_TO_COME * BOARD_RATE) AS
RevenueTotal,
count(DEMAND_TO_COME * BOARD_RATE) as NumofTrans from(
select PA_FCS.ob_location_id,
PA_FCS.ib_location_id,
PA_FCS.vehicle_class,
PA_FCS.return_date,
PA_FCS.RENTAL_DATE,board_rate,
PA_FCS.Demand_to_come,
substr(PA_FCS.rental_date, 0,8) as timestamp
from PA_FCS
inner join pa_reservation on pa_reservation.Rental_date =
PA_FCS.rental_date where booking_value=1
) a
group by a.timestamp
order by a.timestamp;
This should work and give me three columns of the following
Timestamp RevenueTotal NumofTrans
20190220 51435.56745 123665
Not sure what I am doing wrong here.
You could simplify your query like this (you don't need the subquery and some of the fields in it's projection):
SELECT
substr(pa_fcs.rental_date, 0, 8) AS timestamp,
SUM(pa_fcs.demand_to_come * board_rate) AS revenuetotal,
COUNT(*) AS numoftrans
FROM
pa_fcs
INNER JOIN pa_reservation ON pa_reservation.rental_date = pa_fcs.rental_date
WHERE
booking_value = 1
GROUP BY
substr(pa_fcs.rental_date, 0, 8)
ORDER BY
timestamp;
I'm not sure what you are trying to achieve with count(DEMAND_TO_COME * BOARD_RATE). If you want the number of records count(*) should do it.

Why do I get ORA-00907 in my SQL query?

I have this SQL query which a partner has done for a little project at university (this is the first time we use SQL), but we get the ora-00907 error and both of us don't know why.
I have checked the parenthesis and they seem to be ok, so the problem must be another.
select
persona.nombre,
anyo,
t2.total
from persona join
(
select
t1.idPersona,
count(produccion.anyo) as total,
anyo
from
(
select *
from produccion
join pelicula
on produccion.id = pelicula.id
) as pel
join
(
select *
from participa
where idPapel = 8
) as t1
on t1.idProduccion = pel.id
)
group by t1.idPersona
) as t2
on persona.id = t2.idPersona
where t2.total > 2
order by t2.total desc;
You are selecting * and doing group by on one column which is creating problem. Either you select only respective column under group by condition OR you remove group by.
select *
from (produccion join pelicula on produccion.id=pelicula.id) as pel
join
(select *
from participa
where idPapel=8) as t1
on t1.idProduccion=pel.id)
group by t1.idPersona
Above code section is unallowed use of group by.
If group by is so much needed, i would suggest you to use it later on in the end. Another option is to use analytical function and filter out rest un-wanted records in upper nesting of query which you already have.
You have lots of nested views, which makes your query rather hard to debug. You have lots of brackets, which need to match.
Anyway this is wrong: select t1.idPersona, count(produccion.anyo) as total, anyo. You'll need to include anyo in the GROUP BY clause, which will probably change the result set you want.
select persona.nombre,
t2.anyo,
t2.total
from persona join
(select t1.idPersona,
count(produccion.anyo) as total,
anyo
from (select *
from produccion
join pelicula
on produccion.id=pelicula.id) pel
join
(select *
from participa
where idPapel=8) t1
on t1.idProduccion=pel.id
group by t1.idPersona, t1.anyo) t2
on persona.id=t2.idPersona
where t2.total>2
order by t2.total desc;
I think your query can be simplified/corrected like this:
select persona.nombre,
anyo,
t2.total
from persona
join (
select par.idPersona,
count(produccion.anyo) as total,
anyo
from produccion
join pelicula
on produccion.id = pelicula.id
left join participa par
on par.idProduccion = pelicula.id -- or produccion.id,
-- this was also an error in the original query,
-- since the subquery selected both
and par.idPapel = 8
group by t1.idPersona
, anyo -- Was missing, but it also doesn't make sense, as this is what you count, so you'll just get 1's here. What do you want with this?
) as t2
on persona.id = t2.idPersona
where t2.total > 2
order by t2.total desc;

How can I join on multiple columns within the same table that contain the same type of info?

I am currently joining two tables based on Claim_Number and Customer_Number.
SELECT
A.*,
B.*,
FROM Company.dbo.Company_Master AS A
LEFT JOIN Company.dbp.Compound_Info AS B ON A.Claim_Number = B.Claim_Number AND A.Customer_Number = B.Customer_Number
WHERE A.Filled_YearMonth = '201312' AND A.Compound_Ind = 'Y'
This returns exactly the data I'm looking for. The problem is that I now need to join to another table to get information based on a Product_ID. This would be easy if there was only one Product_ID in the Compound_Info table for each record. However, there are 10. So basically I need to SELECT 10 additional columns for Product_Name based on each of those Product_ID's that are being selected already. How can do that? This is what I was thinking in my head, but is not working right.
SELECT
A.*,
B.*,
PD_Info_1.Product_Name,
PD_Info_2.Product_Name,
....etc {Up to 10 Product Names}
FROM Company.dbo.Company_Master AS A
LEFT JOIN Company.dbo.Compound_Info AS B ON A.Claim_Number = B.Claim_Number AND A.Customer_Number = B.Customer_Number
LEFT JOIN Company.dbo.Product_Info AS PD_Info_1 ON B.Product_ID_1 = PD_Info_1.Product_ID
LEFT JOIN Company.dbo.Product_Info AS PD_Info_2 ON B.Product_ID_2 = PD_Info_2.Product_ID
.... {Up to 10 LEFT JOIN's}
WHERE A.Filled_YearMonth = '201312' AND A.Compound_Ind = 'Y'
This query not only doesn't return the correct results, it also takes forever to run. My actual SQL is a lot longer and I've changed table names, etc but I hope that you can get the idea. If it matters, I will be creating a view based on this query.
Please advise on how to select multiple columns from the same table correctly and efficiently. Thanks!
I found put my extra stuff into CTE and add ROW_NUMBER to insure that I get only 1 row that I care about. it would look something like this. I only did for first 2 product info.
WITH PD_Info
AS ( SELECT Product_ID
,Product_Name
,Effective_Date
,ROW_NUMBER() OVER ( PARTITION BY Product_ID, Product_Name ORDER BY Effective_Date DESC ) AS RowNum
FROM Company.dbo.Product_Info)
SELECT A.*
,B.*
,PD_Info_1.Product_Name
,PD_Info_2.Product_Name
FROM Company.dbo.Company_Master AS A
LEFT JOIN Company.dbo.Compound_Info AS B
ON A.Claim_Number = B.Claim_Number
AND A.Customer_Number = B.Customer_Number
LEFT JOIN PD_Info AS PD_Info_1
ON B.Product_ID_1 = PD_Info_1.Product_ID
AND B.Fill_Date >= PD_Info_1.Effective_Date
AND PD_Info_2.RowNum = 1
LEFT JOIN PD_Info AS PD_Info_2
ON B.Product_ID_2 = PD_Info_2.Product_ID
AND B.Fill_Date >= PD_Info_2.Effective_Date
AND PD_Info_2.RowNum = 1

Limit join to one row

I have the following query:
SELECT sum((select count(*) as itemCount) * "SalesOrderItems"."price") as amount, 'rma' as
"creditType", "Clients"."company" as "client", "Clients".id as "ClientId", "Rmas".*
FROM "Rmas" JOIN "EsnsRmas" on("EsnsRmas"."RmaId" = "Rmas"."id")
JOIN "Esns" on ("Esns".id = "EsnsRmas"."EsnId")
JOIN "EsnsSalesOrderItems" on("EsnsSalesOrderItems"."EsnId" = "Esns"."id" )
JOIN "SalesOrderItems" on("SalesOrderItems"."id" = "EsnsSalesOrderItems"."SalesOrderItemId")
JOIN "Clients" on("Clients"."id" = "Rmas"."ClientId" )
WHERE "Rmas"."credited"=false AND "Rmas"."verifyStatus" IS NOT null
GROUP BY "Clients".id, "Rmas".id;
The problem is that the table "EsnsSalesOrderItems" can have the same EsnId in different entries. I want to restrict the query to only pull the last entry in "EsnsSalesOrderItems" that has the same "EsnId".
By "last" entry I mean the following:
The one that appears last in the table "EsnsSalesOrderItems". So for example if "EsnsSalesOrderItems" has two entries with "EsnId" = 6 and "createdAt" = '2012-06-19' and '2012-07-19' respectively it should only give me the entry from '2012-07-19'.
SELECT (count(*) * sum(s."price")) AS amount
, 'rma' AS "creditType"
, c."company" AS "client"
, c.id AS "ClientId"
, r.*
FROM "Rmas" r
JOIN "EsnsRmas" er ON er."RmaId" = r."id"
JOIN "Esns" e ON e.id = er."EsnId"
JOIN (
SELECT DISTINCT ON ("EsnId") *
FROM "EsnsSalesOrderItems"
ORDER BY "EsnId", "createdAt" DESC
) es ON es."EsnId" = e."id"
JOIN "SalesOrderItems" s ON s."id" = es."SalesOrderItemId"
JOIN "Clients" c ON c."id" = r."ClientId"
WHERE r."credited" = FALSE
AND r."verifyStatus" IS NOT NULL
GROUP BY c.id, r.id;
Your query in the question has an illegal aggregate over another aggregate:
sum((select count(*) as itemCount) * "SalesOrderItems"."price") as amount
Simplified and converted to legal syntax:
(count(*) * sum(s."price")) AS amount
But do you really want to multiply with the count per group?
I retrieve the the single row per group in "EsnsSalesOrderItems" with DISTINCT ON. Detailed explanation:
Select first row in each GROUP BY group?
I also added table aliases and formatting to make the query easier to parse for human eyes. If you could avoid camel case you could get rid of all the double quotes clouding the view.
Something like:
join (
select "EsnId",
row_number() over (partition by "EsnId" order by "createdAt" desc) as rn
from "EsnsSalesOrderItems"
) t ON t."EsnId" = "Esns"."id" and rn = 1
this will select the latest "EsnId" from "EsnsSalesOrderItems" based on the column creation_date. As you didn't post the structure of your tables, I had to "invent" a column name. You can use any column that allows you to define an order on the rows that suits you.
But remember the concept of the "last row" is only valid if you specifiy an order or the rows. A table as such is not ordered, nor is the result of a query unless you specify an order by
Necromancing because the answers are outdated.
Take advantage of the LATERAL keyword introduced in PG 9.3
left | right | inner JOIN LATERAL
I'll explain with an example:
Assuming you have a table "Contacts".
Now contacts have organisational units.
They can have one OU at a point in time, but N OUs at N points in time.
Now, if you have to query contacts and OU in a time period (not a reporting date, but a date range), you could N-fold increase the record count if you just did a left join.
So, to display the OU, you need to just join the first OU for each contact (where what shall be first is an arbitrary criterion - when taking the last value, for example, that is just another way of saying the first value when sorted by descending date order).
In SQL-server, you would use cross-apply (or rather OUTER APPLY since we need a left join), which will invoke a table-valued function on each row it has to join.
SELECT * FROM T_Contacts
--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND MAP_CTCOU_SoftDeleteStatus = 1
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID IS NULL -- 989
-- CROSS APPLY -- = INNER JOIN
OUTER APPLY -- = LEFT JOIN
(
SELECT TOP 1
--MAP_CTCOU_UID
MAP_CTCOU_CT_UID
,MAP_CTCOU_COU_UID
,MAP_CTCOU_DateFrom
,MAP_CTCOU_DateTo
FROM T_MAP_Contacts_Ref_OrganisationalUnit
WHERE MAP_CTCOU_SoftDeleteStatus = 1
AND MAP_CTCOU_CT_UID = T_Contacts.CT_UID
/*
AND
(
(#in_DateFrom <= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo)
AND
(#in_DateTo >= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom)
)
*/
ORDER BY MAP_CTCOU_DateFrom
) AS FirstOE
In PostgreSQL, starting from version 9.3, you can do that, too - just use the LATERAL keyword to achieve the same:
SELECT * FROM T_Contacts
--LEFT JOIN T_MAP_Contacts_Ref_OrganisationalUnit ON MAP_CTCOU_CT_UID = T_Contacts.CT_UID AND MAP_CTCOU_SoftDeleteStatus = 1
--WHERE T_MAP_Contacts_Ref_OrganisationalUnit.MAP_CTCOU_UID IS NULL -- 989
LEFT JOIN LATERAL
(
SELECT
--MAP_CTCOU_UID
MAP_CTCOU_CT_UID
,MAP_CTCOU_COU_UID
,MAP_CTCOU_DateFrom
,MAP_CTCOU_DateTo
FROM T_MAP_Contacts_Ref_OrganisationalUnit
WHERE MAP_CTCOU_SoftDeleteStatus = 1
AND MAP_CTCOU_CT_UID = T_Contacts.CT_UID
/*
AND
(
(__in_DateFrom <= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateTo)
AND
(__in_DateTo >= T_MAP_Contacts_Ref_OrganisationalUnit.MAP_KTKOE_DateFrom)
)
*/
ORDER BY MAP_CTCOU_DateFrom
LIMIT 1
) AS FirstOE
Try using a subquery in your ON clause. An abstract example:
SELECT
*
FROM table1
JOIN table2 ON table2.id = (
SELECT id FROM table2 WHERE table2.table1_id = table1.id LIMIT 1
)
WHERE
...

sql query to get distinct records based on created date

I have some records as in the image. I want to write a sql query to fetch the latest unique records so that I only have two records on the basis of UserAlertTicketID and latest Created Date. In this case the output would be like:
"CB23C56F-B067-415E-AD62-59DF4DA4F26D" "2" "2011-03-04 09:49:59.440" "9EDB3DBC-4685-414D-A48B-04CA8285A2D1"
"9FA4D72B-8BB3-4CE9-BCA2-C334AF47EB30" "3" "2011-03-04 09:05:46.817" "94C67A9C-3818-4AB5-A6F6-CD7BD69FAEC7"
Kindly Help!!!
Thanks
SELECT TOP 2 * FROM table GROUP BY UserAlertTicketID ORDER BY CreatedDate DESC
EDIT: this may not do what you want, however try this:
SELECT TOP 2 T1.* FROM Table T1 LEFT JOIN Table T2
ON (T1.AlertTicketEventID = T2.AlertTicketEventID AND T1.CreatedDate < T2.CreatedDate)
WHERE T2.AlertTicketEventID IS NULL ORDER BY T1.CreatedDate DESC
This method will avoid using aggregates and should be much faster.
Something like this?
SELECT
a.AlertTicketEventId,
a.AlertTicketStatusID,
a.CreatedDate,
a.UserAlertTicketID
FROM <Table> a
INNER JOIN (
SELECT
AlertTicketStatusID
,MAX(CreatedDate) AS LastDate
FROM <Table>
GROUP BY AlertTicketStatusID
) b ON a.AlertTicketStatusID = b.AlertTicketStatusID AND a.CreatedDate = b.CreatedDate