Return only one row based on search - sql

Query
select
a.id,
a.ba,
b.status,
b.custid
from balist as a
inner join customer as b
on a.ba = b.ba
I have a table "balist" that has a list of (ba) and i inner join table "customer" on (ba) and right now by output is like the following
id
ba
status
custid
1
ba-1234455
A
123-321-123-321a
2
ba-1234455
I
123-321-123-321a
3
ba-1234457
A
123-321-123-321b
4
ba-1234458
A
123-321-123-321c
5
ba-1234459
I
123-321-123-321d
and I want to return all A and I status but remove the row that has status I that also have a A status. Like the following.
I have a table customer like the following
id
ba
status
custid
1
ba-1234455
A
123-321-123-321a
3
ba-1234457
A
123-321-123-321b
4
ba-1234458
A
123-321-123-321c
5
ba-1234459
I
123-321-123-321d

You could use a row_number() to filter your resulting rows eg
SELECT
id,ba,status,custid
FROM (
SELECT
a.id,
a.ba,
b.status,
b.custid,
ROW_NUMBER() OVER (
PARTITION BY a.ba
ORDER BY b.status ASC
) as rn
FROM
balist as a
INNER JOIN
customer as b ON a.ba = b.ba
)
WHERE rn=1
Let me know if this works for you.

Related

Join two child records next to each other in one row in PL Sql [duplicate]

This question already has an answer here:
Join/Pivot items with EAV table
(1 answer)
Closed 1 year ago.
I have 2 tables,
select * from Srn_Table1;
ID
CUSTOMERNAME
1
TEST CUSTOMER
select * from Srn_Table2;
ID
ADDRESS
ADDRESSID
1
palakkad
1
1
thrissur
2
I need the Result as
ID
ADDRESS
ADDRESSID
ADDRESS
ADDRESSID
1
palakkad
1
thrissur
2
ID is common.
How can I join the 2 tables to get the result..?
I would add a row number to the second table, so that you can join that table once for when that row number is 1, and a second time for when it is 2:
with ext as (
select Srn_Tablea2.*,
row_number() over (partition by id order by addressid) rn
from Srn_Tablea2
)
select a.id, b.address, b.addressid, c.address, c.addressid
from Srn_Tablea1 a
left join ext b on a.id = b.id and b.rn = 1
left join ext c on a.id = c.id and c.rn = 2;
Of course, if you have cases where you have 3 or more addresses for the same id, you'll have to create more joins, and produce more columns. But the principle remains the same.

Combine rows from Mulitple tables into single table

I have one parent table Products with multiple child tables -Hoses,Steeltubes,ElectricCables,FiberOptics.
ProductId -Primary key field in Product table
ProductId- ForeignKey field in Hoses,Steeltubes,ElectricCables,FiberOptics.
Product table has 1 to many relationship with Child tables
I want to combine result of all tables .
For eg - Product P1 has PK field ProductId which is used in all child tables as FK.
If Hoses table has 4 record with ProductId 50 and Steeltubes table has 2 records with ProductId 50 when I perform left join then left join is doing cartesian product of records showing 8 record as result But it should be 4 records .
;with HOSESTEELCTE
as
(
select '' as ModeType, '' as FiberOpticQty , '' as NumberFibers, '' as FiberLength, '' as CableType , '' as Conductorsize , '' as Voltage,'' as ElecticCableLength , s.TubeMaterial , s.TubeQty, s.TubeID , s.WallThickness , s.DWP ,s.Length as SteelLength , h.HoseSeries, h.HoseLength ,h.ProductId
from Hoses h
left join
(
--'' as HoseSeries,'' as HoseLength ,
select TubeMaterial , TubeQty, TubeID , WallThickness , DWP , Length,ProductId from SteelTubes
) s on (s.ProductId = h.ProductId)
) select * from HOSESTEELCTE
Assuming there are no relationships between child tables and you simply want a list of all child entities which make up a product you could generate a cte which has a number of rows which are equal to the largest number of entries across all the child tables for a product. In the example below I have used a dates table to simplify the example.
so for this data
create table products(pid int);
insert into products values
(1),(2);
create table hoses (pid int,descr varchar(2));
insert into hoses values (1,'h1'),(1,'h2'),(1,'h3'),(1,'h4');
create table steeltubes (pid int,descr varchar(2));
insert into steeltubes values (1,'t1'),(1,'t2');
create table electriccables(pid int,descr varchar(2));
truncate table electriccables
insert into electriccables values (1,'e1'),(1,'e2'),(1,'e3'),(2,'e1');
this cte
;with cte as
(select row_number() over(partition by p.pid order by datekey) rn, p.pid
from dimdate, products p
where datekey < 20050105)
select * from cte
create a cartesian join (one of the rare ocassions where an implicit join helps) pid to rn
result
rn pid
-------------------- -----------
1 1
2 1
3 1
4 1
1 2
2 2
3 2
4 2
And if we add the child tables
;with cte as
(select row_number() over(partition by p.pid order by datekey) rn, p.pid
from dimdate, products p
where datekey < 20050106)
select c.pid,h.descr hoses,s.descr steeltubes,e.descr electriccables from cte c
left join (select h.*, row_number() over(order by h.pid) rn from hoses h) h on h.rn = c.rn and h.pid = c.pid
left join (select s.*, row_number() over(order by s.pid) rn from steeltubes s) s on s.rn = c.rn and s.pid = c.pid
left join (select e.*, row_number() over(order by e.pid) rn from electriccables e) e on e.rn = c.rn and e.pid = c.pid
where h.rn is not null or s.rn is not null or e.rn is not null
order by c.pid,c.rn
we get this
pid hoses steeltubes electriccables
----------- ----- ---------- --------------
1 h1 t1 e1
1 h2 t2 e2
1 h3 NULL e3
1 h4 NULL NULL
2 NULL NULL e1
In fact, the result having 8 rows can be expected to be the result, since your four records are joined with the first record in the other table and then your four records are joined with the second record of the other table, making it 4 + 4 = 8.
The very fact that you expect 4 records to be in the result instead of 8 shows that you want to use some kind of grouping. You can group your inner query issued for SteelTubes by ProductId, but then you will need to use aggregate functions for the other columns. Since you have only explained the structure of the desired output, but not the semantics, I am not able with my current knowledge about your problem to determine what aggregations you need.
Once you find out the answer for the first table, you will be able to easily add the other tables into the selection as well, but in case of large data you might get some scaling problems, so you might want to have a table where you store these groups, maintain it when something changes and use it for these selections.

Row_Number() returning duplicate rows

This is my query,
SELECT top 100
UPPER(COALESCE(A.DESCR,C.FULL_NAME_ND)) AS DESCR,
COALESCE(A.STATE, (SELECT TOP 1 STATENAME
FROM M_STATEMASTER
WHERE COUNTRYCODE = B.CODE)) AS STATENAME,
COALESCE(A.STATECD, (SELECT TOP 1 CODE
FROM M_STATEMASTER
WHERE COUNTRYCODE = B.CODE)) AS STATECD,
COALESCE(A.COUNTRYCD, B.CODE) AS COUNTRYCODE
FROM
M_CITY A
JOIN
M_COUNTRYMASTER B ON A.COUNTRYCD = B.CODE
JOIN
[GEODATASOURCE-CITIES-FREE] C ON B.ALPHA2CODE = C.CC_FIPS
WHERE
EXISTS (SELECT 1
FROM [GEODATASOURCE-CITIES-FREE] Z
WHERE B.ALPHA2CODE=Z.CC_FIPS)
ORDER BY
A.CODE
Perfectly working fine, but when I'm trying to get the Row_number() over(order by a.code) I'm getting the duplicate column multiple time.
e.g
SELECT top 100
UPPER(COALESCE(A.DESCR,C.FULL_NAME_ND)) AS DESCR,
COALESCE(A.STATE, (SELECT TOP 1 STATENAME
FROM M_STATEMASTER
WHERE COUNTRYCODE = B.CODE)) AS STATENAME,
COALESCE(A.STATECD, (SELECT TOP 1 CODE
FROM M_STATEMASTER
WHERE COUNTRYCODE = B.CODE)) AS STATECD,
COALESCE(A.COUNTRYCD, B.CODE) AS COUNTRYCODE
ROW_NUMBER() OVER(ORDER BY A.CODE) AS RN -- i made a change here
FROM
M_CITY A
JOIN
M_COUNTRYMASTER B ON A.COUNTRYCD = B.CODE
JOIN
[GEODATASOURCE-CITIES-FREE] C ON B.ALPHA2CODE = C.CC_FIPS
WHERE
EXISTS (SELECT 1
FROM [GEODATASOURCE-CITIES-FREE] Z
WHERE B.ALPHA2CODE=Z.CC_FIPS)
ORDER BY
A.CODE
WHERE
EXISTS (SELECT 1
FROM [GEODATASOURCE-CITIES-FREE] Z
WHERE B.ALPHA2CODE = Z.CC_FIPS)
Another try, when I'm using ROW_NUMBER() OVER(ORDER BY newid()) AS RN it's taking logn time to execute.
Remember: CODE is the Pk of table M_CITY and there is no key in [GEODATASOURCE-CITIES-FREE] table.
Another thing: About JOIN(inner join), Join returns the matched Rows, right???
e.g:
table 1 with 20 rows,
table2 with 30 rows ,
table 3 with 30 rows
If I joined these 3 table on a certain key then the possibility of getting maximum rows is 20, am I right?
Your first query doesn't work fine. It just appears to. The reason is that you are using TOP without an ORDER BY, so an arbitrary set of 100 rows is returned.
When you add ROW_NUMBER(), the query plan changes . . . and the ordering of the result set changes as well. I would suggest that you fix the original query to use a stable sort.

SQL joining two tables with common row

I have 2 tables in sybase
Account_table
Id account_code
1 A
2 B
3 C
Associate_table
id account_code
1 A
1 B
1 C
2 A
2 B
3 A
3 C
I have this sql query
SELECT * FROM account_table account, associate_table assoc
WHERE account.account_code = assoc.account_code
This query will return 7 rows. What I want is to return the rows from associate_table that is only common to the 3 accounts like this:
account id account_code Assoc Id
1 A 1
2 B 1
3 C 1
Can anyone help what kind of join should I do?
SELECT b.id account_id,a.code account_code,a.id assoc_id
FROM associate a,
account b
WHERE a.code = b.code
AND a.id IN (SELECT a.id
FROM associate a,
account b
WHERE a.code = b.code
GROUP BY a.id
HAVING Count(*) = (SELECT Count(*)
FROM account));
NOTE: this query works only if you have unique values in Id and account_code columns in account table. And also, your associate_table should contain unique combination of (id, account,code). i.e., associate table should not contain (1,A) or any pair twice.
Try this
SELECT AC.ID,AC.account_code,ASS.ID
FROM account_table AC INNER JOIN associate_table AS ASS ON AC.account_code = ASS.account_code
OK so far answer is accepted I'll post simpler one:
SELECT *
FROM account_table AS account,
associate_table AS assoc
WHERE account.account_code = assoc.account_code
HAVING (
SELECT
COUNT(*)
FROM associate_table assoc_2
WHERE assoc_2.id = assoc.id
) = 3
here 3 is the number of codes account table has, if it's gonna be dynamic (changing over time),
you can use (SELECT COUNT(*) FROM account_table) instead of exact number. Also I'm sure it will be cached by database engine, so requires less resources

SQL display two results side-by-side

I have two tables, and am doing an ordered select on each of them. I wold like to see the results of both orders in one result.
Example (simplified):
"SELECT * FROM table1 ORDER BY visits;"
name|# of visits
----+-----------
AA | 5
BB | 9
CC | 12
.
.
.
"SELECT * FROM table2 ORDER BY spent;"
name|$ spent
----+-------
AA | 20
CC | 30
BB | 50
.
.
.
I want to display the results as two columns so I can visually get a feeling if the most frequent visitors are also the best buyers. (I know this example is bad DB design and not a real scenario. It is an example)
I want to get this:
name by visits|name by spent
--------------+-------------
AA | AA
BB | CC
CC | BB
I am using SQLite.
Select A.Name as NameByVisits, B.Name as NameBySpent
From (Select C.*, RowId as RowNumber From (Select Name From Table1 Order by visits) C) A
Inner Join
(Select D.*, RowId as RowNumber From (Select Name From Table2 Order by spent) D) B
On A.RowNumber = B.RowNumber
Try this
select
ISNULL(ts.rn,tv.rn),
spent.name,
visits.name
from
(select *, (select count(*) rn from spent s where s.value>=spent.value ) rn from spent) ts
full outer join
(select *, (select count(*) rn from visits v where v.visits>=visits.visits ) rn from visits) tv
on ts.rn = tv.rn
order by ISNULL(ts.rn,tv.rn)
It creates a rank for each entry in the source table, and joins the two on their rank. If there are duplicate ranks they will return duplicates in the results.
I know it is not a direct answer, but I was searching for it so in case someone needs it: this is a simpler solution for when the results are only one per column:
select
(select roleid from role where rolename='app.roles/anon') roleid, -- the name of the subselect will be the name of the column
(select userid from users where username='pepe') userid; -- same here
Result:
roleid | userid
--------------------------------------+--------------------------------------
31aa33c4-4e66-4da3-8525-42689e46e635 | 12ad8c95-fbef-4287-9834-7458a4b250ee
For RDBMS that support common table expressions and window functions (e.g., SQL Server, Oracle, PostreSQL), I would use:
WITH most_visited AS
(
SELECT ROW_NUMBER() OVER (ORDER BY num_visits) AS num, name, num_visits
FROM visits
),
most_spent AS
(
SELECT ROW_NUMBER() OVER (ORDER BY amt_spent) AS num, name, amt_spent
FROM spent
)
SELECT mv.name, ms.name
FROM most_visited mv INNER JOIN most_spent ms
ON mv.num = ms.num
ORDER BY mv.num
Just join table1 and table2 with name as key like bellow:
select a.name,
b.name,
a.NumOfVisitField,
b.TotalSpentField
from table1 a
left join table2 b on a.name = b.name