Combine multiple rows with same value into one row in oracle - sql

I have been trying to solve an Oracle SQL query but to no avail and was hoping i could get some assistance. The scenario is that am querying the database and i get multiple records with the same value and wanted to combine the multiple rows into one.What i want to achieve is have the record for customer with IDNO=22099575 in one row instead of three as it appears in the attached screen shot of my result from my query below
SELECT concat(cu.firstname,cu.secondname)
Customername,cu.customerno,l.idnumber Idno,l.branch_code
Branchcode,l.phonenumber
Phone,cu.gender,l.grade,l.arocode,l.loanaccount,l.duedate,l.interest,
l.outstandingamount Outstandingloanbal,
l.lien Lienamount,TO_CHAR(l.applicationdate,'DD-MM-YY')
applicationdate,l.lastpaymentdate Lastcreditdate,l.inarrears
Principalloaninarrears,
l.rebate_amount Rebatepayable, l.empcode, l.disbursaldate, lt.description
Producttype,sum(l.amountdisbursed) Disbursedamt,
l.loanamount Principalamount,l.interest
Interestamount,l.flexi_refno,l.active
FROM ((ebank.tbloanaccount l
INNER JOIN ebank.tbcustomers cu ON l.customerno = cu.customerno)
INNER JOIN ebank.tbloantype lt ON l.productcode = lt.productcode)
where l.DISBURSED = '1'
group by concat(cu.firstname,cu.secondname), cu.customerno, l.idnumber,
l.branch_code, l.phonenumber,
cu.gender, l.grade, l.arocode, l.loanaccount,
l.duedate, l.interest, l.outstandingamount, l.lien,
TO_CHAR(l.applicationdate,'DD-MM-YY'),
l.lastpaymentdate, l.inarrears, l.rebate_amount, l.empcode, l.disbursaldate,
lt.description, l.loanamount, l.interest, l.flexi_refno, l.active order by
l.disbursaldate desc;
Here is a screen shot of my results from the above query:

you can use dense_rank on queries, to get latest due_date, outstanding loan.
SELECT concat(cu.firstname,cu.secondname)
Customername,cu.customerno,l.idnumber Idno,l.branch_code
Branchcode,l.phonenumber
Phone,cu.gender,l.grade,l.arocode,l.loanaccount, max(l.duedate) keep ( dense_rank first order by l.duedate desc ) duedate,l.interest,
max(l.outstandingamount) keep ( dense_rank first order by l.duedate desc ) Outstandingloanbal,
l.lien Lienamount,TO_CHAR(l.applicationdate,'DD-MM-YY')
applicationdate,l.lastpaymentdate Lastcreditdate,l.inarrears
Principalloaninarrears,
l.rebate_amount Rebatepayable, l.empcode, l.disbursaldate, lt.description
Producttype,sum(l.amountdisbursed) Disbursedamt,
l.loanamount Principalamount,l.interest
Interestamount,l.flexi_refno,l.active
FROM ((ebank.tbloanaccount l
INNER JOIN ebank.tbcustomers cu ON l.customerno = cu.customerno)
INNER JOIN ebank.tbloantype lt ON l.productcode = lt.productcode)
where l.DISBURSED = '1'
group by concat(cu.firstname,cu.secondname), cu.customerno, l.idnumber,
l.branch_code, l.phonenumber,
cu.gender, l.grade, l.arocode, l.loanaccount,
l.duedate, l.interest, l.outstandingamount, l.lien,
TO_CHAR(l.applicationdate,'DD-MM-YY'),
l.lastpaymentdate, l.inarrears, l.rebate_amount, l.empcode, l.disbursaldate,
lt.description, l.loanamount, l.interest, l.flexi_refno, l.active order by
l.disbursaldate desc;

Related

where statement execute before inner join

I'm trying to grab the first instance of each result with a sysAddress of less than 4. However my statement currently grabs the min(actionTime) result first before applying the where sysAddress < 4. I'm trying to have the input for the inner join as the where sysAddress < 4 however i cant seem to figure out how to do it.
Should i be nesting it all differently? I didnt want to create an additional layer of table joins. Is this possible? I'm a bit lost at all the answers ive found.
SELECT
tblHistoryObject.info,
tblHistory.actionTime,
tblHistoryUser.userID,
tblHistoryUser.firstName,
tblHistoryUser.surname,
tblHistory.eventID,
tblHistoryObject.objectID,
tblHistorySystem.sysAddress
FROM tblHistoryObject
JOIN tblHistory
ON (tblHistory.historyObjectID = tblHistoryObject.historyObjectID)
JOIN tblHistorySystem
ON (tblHistory.historySystemID = tblHistorySystem.historySystemID)
JOIN tblHistoryUser
ON (tblHistory.historyUserID = tblHistoryUser.historyUserID)
INNER JOIN (SELECT
MIN(actionTime) AS recent_date,
historyObjectID
FROM tblHistory
GROUP BY historyObjectID) AS t2
ON t2.historyObjectID = tblHistoryObject.historyObjectID
AND tblHistory.actionTime = t2.recent_date
WHERE sysAddress < 4
ORDER BY actionTime ASC
WITH
all_action_times AS
(
SELECT
tblHistoryObject.info,
tblHistory.actionTime,
tblHistoryUser.userID,
tblHistoryUser.firstName,
tblHistoryUser.surname,
tblHistory.eventID,
tblHistoryObject.objectID,
tblHistorySystem.sysAddress,
ROW_NUMBER() OVER (PARTITION BY tblHistoryObject.historyObjectID
ORDER BY tblHistory.actionTime
)
AS historyObjectID_SeqByActionTime
FROM
tblHistoryObject
INNER JOIN
tblHistory
ON tblHistory.historyObjectID = tblHistoryObject.historyObjectID
INNER JOIN
tblHistorySystem
ON tblHistory.historySystemID = tblHistorySystem.historySystemID
INNER JOIN
tblHistoryUser
ON tblHistory.historyUserID = tblHistoryUser.historyUserID
WHERE
tblHistorySystem.sysAddress < 4
)
SELECT
*
FROM
all_action_times
WHERE
historyObjectID_SeqByActionTime = 1
ORDER BY
actionTime ASC
This does exactly what your original query did, without trying to filter by action_time.
Then it appends a new column, using ROW_NUMBER() to generate sequences from 1 for each individual tblHistoryObject.historyObjectID. Then it takes only the rows where this sequence value is 1 (the first row per historyObjectID, when sorted in action_time order).

How can I limit the results extracted by a query in Acces?

I have this query in my Access database:
SELECT t_Campioni_CAMPIONE, t_Campioni.[DATA ARRIVO], t_Campioni.PRODUTTORE, t_Campioni.CodF, t_Fornitori.[Nome Fornitore]
FROM t_Campioni INNER JOIN t_Fornitori ON t_Campioni.CodF = t_Fornitori.CodF
WHERE (((t_Campioni.CAMPIONE)=[Forms]![m_Campioni_modifica]![CAMPIONE]))
ORDER BY t_Campioni.[DATA ARRIVO] DESC;
It works but I need it to extract only the first record (with the last date). How can I do it?
Just replace your initial SELECT by SELECT TOP 1
SELECT TOP 1 t_Campioni_CAMPIONE, t_Campioni.[DATA ARRIVO], t_Campioni.PRODUTTORE, t_Campioni.CodF, t_Fornitori.[Nome Fornitore]
FROM t_Campioni INNER JOIN t_Fornitori ON t_Campioni.CodF = t_Fornitori.CodF
WHERE (((t_Campioni.CAMPIONE)=[Forms]![m_Campioni_modifica]![CAMPIONE]))
ORDER BY t_Campioni.[DATA ARRIVO] DESC;
SELECT t_Campioni_CAMPIONE, t_Campioni.[DATA ARRIVO], t_Campioni.PRODUTTORE,
t_Campioni.CodF, t_Fornitori.[Nome Fornitore]
FROM t_Campioni INNER JOIN t_Fornitori ON t_Campioni.CodF = t_Fornitori.CodF
WHERE (((t_Campioni.CAMPIONE)=[Forms]![m_Campioni_modifica]![CAMPIONE]))
ORDER BY t_Campioni.[DATA ARRIVO] DESC LIMIT 1;
You should use TOP/LIMIT/ROWNUM depends on your RDBM.
For more info: http://www.w3schools.com/sql/sql_top.asp

Combine two SQL Queries to prevent having to use a loop

I need to combine two SQL Queries and I'm hurting myself trying to think through it. My first query gets the number of visitors per day and the second query gets the number of unique visitors per day.
Query 1 - For getting the number of visits
SELECT Count(server_instances.game_id) AS visit_count,
refined_player_visits.visit_date AS visit_date
FROM work.refined_player_visits
INNER JOIN tapi.server_instances
ON server_instances.server_id = refined_player_visits.server_id
WHERE ( server_instances.game_id = "31" )
GROUP BY visit_date;
Query 2 - For getting the number of unique visits
SELECT Count(visit_counts.unique_visit_date) AS unique_visits
FROM (SELECT Count(refined_player_visits.server_id) AS visit_count,
refined_player_visits.visit_date AS unique_visit_date
FROM refined_player_visits
INNER JOIN server_instances
ON server_instances.server_id =
refined_player_visits.server_id
WHERE ( server_instances.place_id = "31"
AND refined_player_visits.visit_date <= CURRENT_VISIT_DATE )
GROUP BY refined_player_visits.roblox_id) AS visit_counts
WHERE ( visit_counts.visit_date = CURRENT_VISIT_DATE
AND visit_counts.visit_count = 1 )
Because this was originally for a web application, I got the results back from the first query and looped through each one. During each loop I would do the second query (where CURRENT_VISIT_DATE is actually the visit_date from the first query.
I'd like to turn this into one query using a JOIN, perhaps. I'm migrating to another system and I don't have the option of doing a second query in the loop statement, so I want to just combine the two queries. I can't seem to wrap my head around it, though.
Does this return what you want?
SELECT *
FROM
(
SELECT Count(server_instances.game_id) AS visit_count,
refined_player_visits.visit_date AS visit_date
FROM work.refined_player_visits
INNER JOIN tapi.server_instances
ON server_instances.server_id = refined_player_visits.server_id
WHERE ( server_instances.game_id = "31" )
GROUP BY visit_date
) AS FirstQuery,
(
SELECT Count(visit_counts.unique_visit_date) AS unique_visits
FROM (SELECT Count(refined_player_visits.server_id) AS visit_count,
refined_player_visits.visit_date AS unique_visit_date
FROM refined_player_visits
INNER JOIN server_instances
ON server_instances.server_id =
refined_player_visits.server_id
WHERE (server_instances.place_id = "31"
AND refined_player_visits.visit_date <= FirstQuery.visit_date)
GROUP BY refined_player_visits.roblox_id) AS visit_counts
WHERE ( visit_counts.visit_date = FirstQuery.visit_date
AND visit_counts.visit_count = 1 )
) AS SecondQuery

How get specific rows in grouped result

i need to group some data but because there are 4 store images , sql query return 4 result for every store. How can i get only one for a store by using sql query ?
select s.name,si.SHOP_IMG_PATH,count(*) amount from stab t
inner join shop s on (s.shop_id = t.shop_id)
inner join SHOP_IMG si on (s.shop_id= si.SHOP_ID)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name,si.SHOP_IMG_PATH
order by 3 desc,1 asc
As you see below image there a re 4 images so query can give random image
You are grouping by s.name, si.SHOP_IMG_PATH it will consider all possible combination of s.name, si.SHOP_IMG_PATH as separate you need to keep group by only s.name
Try this
SELECT a.NAME, a.PATH, a.AMOUNT
FROM (select
s.name AS 'NAME', si.SHOP_IMG_PATH AS 'PATH', count(*) AS 'AMOUNT',
ROW_NUMBER() OVER(PARTITION BY s.name
ORDER BY type si.SHOP_IMG_PATH) AS rk
from
stab t
inner join shop s on (s.shop_id = t.shop_id)
inner join SHOP_IMG si on (s.shop_id= si.SHOP_ID)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name
order by 3 desc,1 asc) a
WHERE a.rk = 1;
Alternative
You will get result but this is just a workaround and easy alternative to your problem but not a good one.
select s.name AS 'NAME', min(si.SHOP_IMG_PATH) AS 'PATH', count(*) AS 'AMOUNT',
from
stab t
inner join shop s on (s.shop_id = t.shop_id)
inner join SHOP_IMG si on (s.shop_id= si.SHOP_ID)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name
order by 3 desc,1 asc
This second query will return result as per your need
group by s.name, si.SHOP_IMG_PATH
You're telling it to differentiate them according to SHOP_IMG_PATH. Hence, it shows 4 results, one for each of those.
You'll have to drop SHOP_IMG_PATH from the select clause, if you won't let it use it.
Edit
Got your comment. What you're looking for is random aggregation. This is achieved diferently on different SQL engines. Google around for the one you're using.
If it's Oracle, as indicated by the question tag, here
I solved my problem by using below query,
select s.name,t.shop_id,(select min(SHOP_IMG_PATH) from SHOP_IMG si where shop_id =t.shop_id),count(*) amount from stab t
inner join shop s on (s.shop_id = t.shop_id)
where t.acct_id = 111 and t.CR_DATE >= sysDate - 1
group by s.name,t.shop_id
order by 4 desc,1 asc

SQL - Derived tables issue

I have the following SQL query:
SELECT VehicleRegistrations.ID, VehicleRegistrations.VehicleReg,
VehicleRegistrations.Phone, VehicleType.VehicleTypeDescription,
dt.ID AS 'CostID', dt.IVehHire, dt.FixedCostPerYear, dt.VehicleParts,
dt.MaintenancePerMile, dt.DateEffective
FROM VehicleRegistrations
INNER JOIN VehicleType ON VehicleRegistrations.VehicleType = VehicleType.ID
LEFT OUTER JOIN (SELECT TOP (1) ID, VehicleRegID, DateEffective, IVehHire,
FixedCostPerYear, VehicleParts, MaintenancePerMile
FROM VehicleFixedCosts
WHERE (DateEffective <= GETDATE())
ORDER BY DateEffective DESC) AS dt
ON dt.VehicleRegID = VehicleRegistrations.ID
What I basically want to do is always select the top 1 record from the 'VehicleFixedCosts' table, where the VehicleRegID matches the one in the main query. What is happening here is that it's selecting the top row before the join, so if the vehicle registration of the top row doesn't match the one we're joining to it returns nothing.
Any ideas? I really don't want to have use subselects for each of the columns I need to return
Try this:
SELECT vr.ID, vr.VehicleReg,
vr.Phone, VehicleType.VehicleTypeDescription,
dt.ID AS 'CostID', dt.IVehHire, dt.FixedCostPerYear, dt.VehicleParts,
dt.MaintenancePerMile, dt.DateEffective
FROM VehicleRegistrations vr
INNER JOIN VehicleType ON vr.VehicleType = VehicleType.ID
LEFT OUTER JOIN (
SELECT ID, VehicleRegID, DateEffective, IVehHire, FixedCostPerYear, VehicleParts, MaintenancePerMile
FROM VehicleFixedCosts vfc
JOIN (
select VehicleRegID, max(DateEffective) as DateEffective
from VehicleFixedCosts
where DateEffective <= getdate()
group by VehicleRegID
) t ON vfc.VehicleRegID = t.VehicleRegID and vfc.DateEffective = t.DateEffective
) AS dt
ON dt.VehicleRegID = vr.ID
Subquery underneath dt might need some grouping but without schema (and maybe sample data) it's hard to say which column should be involved in that.