MariaDB concatenate 2 tables with same number of rows - sql

Say I have 2 tables with exactly SAME number of rows, but no other obvious relations:
tableA
ID
items
1
banana
2
orange
tableB
itemID
volume
5550
50
5551
70
Can I join these 2 tables horizontally, to form 1 table like the following?
ID
items
itemID
volume
1
banana
5550
50
2
orange
5551
70

If you have 2 tables with exactly SAME number of rows, but no other obvious relations and on both tables , respectively ID and itemID defines the uniqueness of the rows you can apply MySQL ROW_NUMBER Function and join on the row_number, the order by clause is important.
Try:
SELECT tbla.ID, tbla.Items, tblb.ItemId, tblb.volume
FROM (
SELECT ID, Items, row_number() over( order by ID desc )row_numA
FROM TableA
)tbla
INNER join
( SELECT ItemId,volume,row_number() over(order by ItemId desc)row_numB
FROM TableB
) tblb ON tbla.row_numA=tblb.row_numB
order by tbla.ID asc;
https://dbfiddle.uk/?rdbms=mariadb_10.6&fiddle=15d13d29a84a55c4d029115c87eebe8f

try this
create table TableA(ID INT, Items varchar(20));
create table TableB(ItemId INT, volume varchar(20));
insert into TableA(Id, items) values (1, 'banana'), (2, 'orange');
insert into TableB(ItemId, volume) values (5550, '50'), (5551, '70');
SELECT A.ID, A.Items, B.ItemId, B.volume
FROM
(
SELECT ID, Items, rownum()R
FROM TableA
)A INNER join
(
SELECT ItemId,volume,rownum()R
FROM TableB
)B ON A.R=B.R

Related

Lookup a value on another table with no relationship

In TSQL, how do we select a value from a table with no relationship to the other.
I'm trying to select what rank an ID has, by looking up their score in another table. I was going to join and then use a 'where Score between From and TO' but, I had no luck joining.
Table_A
ID
Score
A
67
B
569
C
123
Table_B
From
To
Rank
1
99
Top100
100
499
Top500
500
999
Top1000
Expected query result:
ID
Rank
A
Top100
B
Top1000
C
Top500
I started with
Select ID From Table_A
Inner Join
I got lost here because there is no relationship
I could get the result using a scalar function, but in terms of performance, where Table_A has over 500k rows, it seemed a little sluggish because Table_B not only holds rank, but has other columns I need for the query.
For example:
Table_B
From
To
Rank
Level
Color
Category
1
99
Top100
Gold
Green
1
100
499
Top500
Silver
Yellow
5
500
999
Top1000
Bronze
Red
100
Basically, if I can be shown how to query at least the rank, I can get the other columns as well.
You can use BETWEEN as the JOIN condition, like so:
CREATE TABLE #Table_A
(
ID VARCHAR(255),
Score INT
)
;
INSERT #Table_A ([ID], [Score]) VALUES
('A', 67),
('B', 569),
('C', 123);
CREATE TABLE #Table_B
(
[From] INT,
[To] INT,
[Rank] VARCHAR(255)
)
INSERT #Table_B ([From], [To], [Rank]) VALUES
( 1, 99, 'Top100'), (100, 499, 'Top500'), (500, 999, 'Top1000');
-- Query here
SELECT A.[ID], B.[Rank]
FROM #Table_A A
INNER JOIN #Table_B B ON A.Score BETWEEN B.[From] AND B.[To]
You could also use CROSS APPLY to get your favorite result
;WITH Table_A AS
(
SELECT 'A' ID, 67 Score
Union
SELECT 'B' ID, 569 Score
Union
SELECT 'C' ID, 123 Score
),
Table_B AS
(
SELECT 1 [From], 99 [To], 'Top100' [Rank]
Union
SELECT 100 [From], 499 [To], 'Top500' [Rank]
Union
SELECT 500 [From], 999 [To], 'Top1000' [Rank]
)
SELECT Table_A.[ID], Table_B.[Rank]
FROM Table_A
CROSS APPLY Table_B
WHERE Table_A.Score
BETWEEN Table_B.[From] AND Table_B.[To]
GO

Merge or join two tables SQL Server

I have a table with two columns Item, Qty and another table with Product, Quantity.
Table A
Item
Qty
a
10
a
15
a
5
b
10
Table b
Product
Quantity
a
10
a
20
b
5
b
5
The output that I'm looking for is this:
item
Qty
Product
Quantity
a
10
a
10
a
15
a
20
a
5
NULL
NULL
b
10
b
5
NULL
NULL
b
5
You will need to have some sort of order to guarantee consistent results. To simulate that, I added IDENTITY columns
Match Product to Item in Order Based on ROW_NUMBER()
DROP TABLE IF EXISTS #Table1
DROP TABLE IF EXISTS #Table2
CREATE TABLE #Table1 (ID INT IDENTITY(1,1),Item CHAR(1),Qty INT)
CREATE TABLE #Table2 (ID INT IDENTITY(1,1),Product CHAR(1),Qty INT)
INSERT INTO #Table1
VALUES ('a',10)
,('a',15)
,('a',5)
,('b',10)
INSERT INTO #Table2
VALUES ('a',10)
,('a',20)
,('b',5)
,('b',5)
;WITH cte_Table1 AS (
SELECT *,RankNum = ROW_NUMBER() OVER (PARTITION BY Item ORDER BY ID)
FROM #Table1
),
cte_Table2 AS (
SELECT *,RankNum = ROW_NUMBER() OVER (PARTITION BY Product ORDER BY ID)
FROM #Table2
)
SELECT *
FROM cte_Table1 AS A
FULL JOIN cte_Table2 AS B
ON A.Item = B.Product
AND A.RankNum = B.RankNum

Sql join only 1 row

I want to join the table CustomerAgreementRole with only one row from AgreementRoleGroup, based on ViewPriority. Example: CustomerAgreementRole can have three rows. I only want the joined row where ViewPriority is highest
AgreementId, AgreementRoleId
1 1
1 2
1 3
CustomerAgreementRole
1. AgreementId
2. AgreementRoleId
AgreementRoleGroup
1. AgreementRoleId
2. ViewPriority
Current query:
select * from CustomerAgreementRole car
join (select agreementRoleId, min(ViewPriority) as mi from AgreementRoleGroup group by AgreementRoleId) as arg on car.AgreementRoleId = arg.AgreementRoleId
Expected result:
AgreementId, AgreementRoleId, ViewPriority
1 1 1
May be something like this:
SELECT *
FROM CustomerAgreementRole A
CROSS APPLY
(
SELECT TOP 1 *
FROM AgreementRoleGroup B
WHERE A.[AgreementRoleId] = B.[AgreementRoleId]
ORDER BY ViewPriority DESC
) C
Since AgreementRoleGroup already got AgreementRoleId we can just join with some subquery
select a.*, b2.ViewPriority from CustomerAgreementRole a left join
(
select b.AgreementRoleId, b.ViewPriority
from AgreementRoleGroup b
where b.ViewPriority =
(
select min(ViewPriority)
from AgreementRoleGroup
)
) b2
on a.AgreementRoleId=b2.AgreementRoleId
But I'll say that using min() isn't the best way,you should use top in #gotqn answer but right now this will work.
re-edit
create table CustomerAgreementRole (AgreementId int,AgreementRoleId int);
insert into CustomerAgreementRole values (1,1);
insert into CustomerAgreementRole values (2,3);
insert into CustomerAgreementRole values (3,4);
insert into CustomerAgreementRole values (4,2);
create table AgreementRoleGroup (AgreementRoleId int, ViewPriority int);
insert into AgreementRoleGroup values (1,3);
insert into AgreementRoleGroup values (3,4);
insert into AgreementRoleGroup values (4,2);
insert into AgreementRoleGroup values (2,1);
I use those as sample data and got this result db<>fiddle
if you just want that one row and don't care ViewPriority need to be min, use top instead
select top 1 a.*, b.ViewPriority from CustomerAgreementRole a left join
AgreementRoleGroup b
on a.AgreementRoleId=b.AgreementRoleId
order by ViewPriority asc
Per AgreementId you want the AgreementRoleId with the highest priority (lowest ViewPriority value). This means you want to rank the CustomerAgreementRole rows and only show the best ranked ones. Ranking is typically done with ROW_NUMBER, RANK or DENSE_RANK in SQL.
select AgreementId, AgreementRoleId, ViewPriority
from
(
select
car.AgreementId, car.AgreementRoleId, arg.ViewPriority,
row_number() over (partition by car.AgreementId order by arg.ViewPriority) as rn
from CustomerAgreementRole car
join AgreementRoleGroup arg on arg.AgreementRoleId = car.AgreementRoleId
) ranked
where rn = 1;
Made it working with this:
WITH CTEViewPriority (lowestViewPriority, agreementId) as (
select min(ViewPriority), AgreementId from CustomerAgreementRole as car
left join AgreementRoleGroup arg on car.AgreementRoleId = arg.AgreementRoleId
group by agreementId
)
select * from CustomerAgreementRole as car
inner join CTEViewPriority as arg on lowestViewPriority = arg.agreementRoleId and arg.agreementId = car.agreementId

Counting the count of distinct values from two columns in sql

I have a table in data base in which there are corresponding values for the primary key.
I want to count the distinct values from two columns.
I already know one method of using union all and then applying groupby on that resultant table.
Select Id,Brand1
into #Temp
from data
union all
Select Id,Brand2
from data
Select ID,Count(Distinct Brand1)
from #Temp
group by ID
Same thing we can do in big query also using temp table only.
Sample Table
ID Brand1 Brand2
1 A B
1 B C
2 D A
2 A D
Resultant Table
ID Distinct_Count_Brand
1 3
2 2
As you can see in this column Distinct_count_Brand It is counting the unique count of Brand from two columns Brand1 and Brand2.
I already know one way (Basically unpivoting) but want to know if there is some other way around to count unique values from two columns.
I don't know BigQuery's quirks, but perhaps you can just inline the union query:
SELECT ID, COUNT(DISTINCT Brand)
FROM
(
SELECT ID, Brand1 AS Brand FROM data
UNION ALL
SELECT ID, Brand2 FROM data
) t
GROUP BY ID;
In SQL Server, I woud use:
Select b.id, count(distinct b.brand)
from data d cross apply
(values (id, brand1), (id, brand2)) b(id, brand)
group by b.id;
Here is a db<>fiddle.
In BigQuery, the equivalent would be expressed as:
select t.id, count(distinct brand)
from t cross join
unnest(array[brand1, brand2]) brand
group by t.id;
Here is a BQ query that demonstrates that this works:
with t as (
select 1 as id, 'A' as brand1, 'B' as brand2 union all
select 1, 'B', 'C' union all
select 2, 'D', 'A' union all
select 2, 'A', 'D'
)
select t.id, count(distinct brand)
from t cross join
unnest(array[brand1, brand2]) brand
group by t.id;

SQL Server : SELECT ID having only a single condition

I have a patients table with details such as conditions that the patient has. from the below table I want to select Patients, Claims which have ONLY a single condition - 'Hypertension'. Example Patient B is the expected output. Patient A will not be selected because he claimed for multiple conditions.
+----+---------+--------------+
| ID | ClaimID | Condition |
+----+---------+--------------+
| A | 14234 | Hypertension |
| A | 14234 | Diabetes |
| A | 63947 | Diabetes |
| B | 23853 | Hypertension |
+----+---------+--------------+
I tried using the NOT IN condition as below but doesn't seem to help
SELECT ID, ClaimID, Condition
FROM myTable
WHERE Condition IN ('Hypertension')
AND Condition NOT IN ('Diabetes')
One method uses not exists:
select t.*
from mytable t
where t.condition = 'Hypertension' and
not exists (select 1
from mytable t2
where t2.id = t.id and t2.condition <> t.condition
);
Or you can do it like this:
select
id,
claim_id,
condition
from
patient
where
id in
(
select
id
from
patient
group by
id having count (distinct condition) = 1
);
Result:
id claim_id condition
-- ----------- ----------------
B 23853 Hypertension
(1 rows affected)
Setup:
create table patient
(
id varchar(1),
claim_id int,
condition varchar(16)
);
insert into patient (id, claim_id, condition) values ('A', 14234, 'Hypertension');
insert into patient (id, claim_id, condition) values ('A', 14234, 'Diabetes');
insert into patient (id, claim_id, condition) values ('A', 63947, 'Diabetes');
insert into patient (id, claim_id, condition) values ('B', 23853, 'Hypertension');
You can do this with a CTE.
I set up this CTE with two parameters, one being the Condition you seek, and the other being the max number of combined conditions to find (in your case 1).
DECLARE #myTable TABLE (Id VARCHAR(1), ClaimID INT, Condition VARCHAR(100))
INSERT INTO #myTable (Id, ClaimID, Condition)
SELECT 'A',14234,'Hypertension' UNION ALL
SELECT 'A',14234,'Diabetes' UNION ALL
SELECT 'A',63947,'Diabetes' UNION ALL
SELECT 'B',23853,'Hypertension'
DECLARE #Condition VARCHAR(100)
DECLARE #MaxConditions TINYINT
SET #Condition='Hypertension'
SET #MaxConditions=1
; WITH CTE AS
(
SELECT *, COUNT(2) OVER(PARTITION BY ClaimID) AS CN
FROM #myTable T1
WHERE EXISTS (SELECT 1 FROM #myTable T2 WHERE T1.ClaimID=T2.ClaimID AND T2.Condition=#Condition)
)
SELECT *
FROM CTE
WHERE CN<=#MaxConditions
If you don't care about the fluff, and just want all ClaimID's with just ONE condition regardless of which condition it is use this.
DECLARE #myTable TABLE (Id VARCHAR(1), ClaimID INT, Condition VARCHAR(100))
INSERT INTO #myTable (Id, ClaimID, Condition)
SELECT 'A',14234,'Hypertension' UNION ALL
SELECT 'A',14234,'Diabetes' UNION ALL
SELECT 'A',63947,'Diabetes' UNION ALL
SELECT 'B',23853,'Hypertension'
DECLARE #MaxConditions TINYINT
SET #MaxConditions=1
; WITH CTE AS
(
SELECT *, COUNT(2) OVER(PARTITION BY ClaimID) AS CN
FROM #myTable T1
)
SELECT *
FROM CTE
WHERE CN<=#MaxConditions
Here is one method using Having clause
SELECT t.*
FROM mytable t
WHERE EXISTS (SELECT 1
FROM mytable t2
WHERE t2.id = t.id
HAVING Count(CASE WHEN condition = 'Hypertension' THEN 1 END) > 0
AND Count(CASE WHEN condition != 'Hypertension' THEN 1 END) = 0)
And yet a couple of other ways to do this:
declare #TableA table(Id char,
ClaimId int,
Condition varchar(250));
insert into #TableA (id, claimid, condition)
values ('A', 14234, 'Hypertension'),
('A', 14234, 'Diabetes'),
('A', 63947, 'Diabetes'),
('B', 23853, 'Hypertension')
select id, claimid, condition
from #TableA a
where not exists(select id
from #TableA b
where a.id = b.id
group by b.id
having count(b.id) > 1)
OR
;with cte as
(
select id, claimid, condition
from #TableA
)
,
cte2 as
(
Select id, count(Id) as counts
from cte
group by id
having count(id) < 2
)
Select cte.id, claimid, condition
From cte
inner join
cte2
on cte.id = cte2.id
I decided to revise my answer into an appropriate one.
A simple solution to your question is to count the rows instead of the ID values (since it's not an integer).
Here is a simple introduction:
SELECT
ID
FROM
#PatientTable
GROUP BY
ID
HAVING
ID = ID AND COUNT(*) = 1
This will Return the ID B
+----+
| ID |
+----+
| B |
+----+
Surely, this is not enough, as you may work with a large data and need more filtering.
So, we will go and use it as a sub-query.
Using it as a sub-query it's simple :
SELECT
ID,
ClaimID,
Condition
FROM
#PatientTable
WHERE
ID = (SELECT ID AS NumberOfClaims FROM #PatientTable GROUP BY ID HAVING ID = ID AND COUNT(*) = 1)
This will return
+----+---------+--------------+
| ID | ClaimID | Condition |
+----+---------+--------------+
| B | 23853 | Hypertension |
+----+---------+--------------+
So far so good, but there is another issue we may face. Let's say you have a multiple Claims from a multiple patients, using this query as is will only show one patient. To show all patients we need to use IN rather than = under the WHERE clause
WHERE
ID IN (SELECT ID AS NumberOfClaims FROM #PatientTable GROUP BY ID HAVING ID = ID AND COUNT(*) = 1)
This will list all patients that falls under this condition.
If you need more conditions to filter, you just add them to the WHERE clause and you'll be good to go.
SELECT id, sum(ct)
FROM (SELECT customer_id, CASE WHEN category = 'X' THEN 0 else 1
end ct
FROM MASTER_TABLE
) AS t1
GROUP BY id
HAVING sum(ct) = 0
id which will have sum(ct) more than 1, will have multiple conditions
Use joins instead of subquery. Joins are always better in performance. You can use below query.
SELECT T1.id, T1.claimid, T1.Condition
FROM mytable T1
INNER JOIN
(
select id, count(Condition) counter
from mytable
group by id HAVING COUNT(DISTINCT CONDITION)=1
) T2 ON T1.ID=T2.ID
WHERE T2.counter=1