I've got the following tables:
Table1 {ArticleNo (int), ArtDescription (string) }
Table2 { ArticleNo (int), Year (date) }
Table1.ArticleNo is a primary key.
Table2.ArticleNo is a foreign key referenced to table1.ArticleNo
It's difficult to explain what I want to query, so here a short example:
Table1
(1,Desk)
(2,Chair)
(3,Ruler)
Table2
(1,2000)
(1,2000)
(2,2001)
The query should return:
1 Desk 2001
2 Chair 2000
3 Ruler 2000
3 Ruler 2001
All articles which are not sold (or whatever) in all years (all years from table2).
I hope you understand my example - the query seems to be very complex. Here my approach to a solution:
SELECT table1.ArticleNo,table1.ArtDescription,table2.Year
FROM table1
JOIN table2
ON table1.ArticleNo=table2.ArticleNo
WHERE NOT table1.ArticleNo IN (SELECT table2.Year FROM table2);
I tried lots of different things.. I hope you can help me!
SELECT t1.*, t2.year
FROM t1
CROSS JOIN
(
SELECT DISTINCT year
FROM t2
) t2
WHERE (t1.id, t2.year) NOT IN
(
SELECT t2.id, t2.year
FROM t2
)
Create an index on t2 (year, id) (in this order) for the query to work fast.
You could use a cross join to create a list of all item+year combinations. Then you could filter the rows without sales with a not exists condition:
select *
from t1 items1
cross join
(
select distinct year
from t2 sales1
) sales2
where not exists
(
select *
from t2 sales3
where sales3.ItemId = items1.ItemId
and sales3.Year = sales2.Year
)
There are a bunch of ways of doing this. Two examples:
select
t1.ArtDescription,
y.Year
from
Table1 t1
join (
select distinct
t2.Year
from
Table2 t2
) y on 1=1
where
not exists (
select
1
from
Table2 tx2
where
tx2.ArticleNo = t1.ArticleNo and tx2.Year = y.Year)
Oracle (SQL Server can do the same thing, use EXCEPT instead of MINUS):
select
t1.ArtDescription,
y.Year
from
Table1 t1
join (
select distinct
t2.Year
from
Table2 t2
) y on 1=1
MINUS
select
t12.ArtDescription
t22.Year
from
Table1 t12
join Table2 t22 on t12.ArticleNo = t22.ArticleNo
SELECT DISTINCT table1.ArticleNo,table1.ArtDescription,table2.Year
FROM table1 CROSS JOIN table2
WHERE table1.ArticleNo != table2.ArticleNo order by table1.ArticleNo;
Related
I have about 10 tables that I make one big nested tables by rounds with the following query:
R1 AS(
SELECT ANY_VALUE(Table1).*, ARRAY_AGG(( SELECT AS STRUCT Table2.* EXCEPT(ID))) AS Table2
FROM Table1 LEFT JOIN Table2 USING(ID)
GROUP BY Table1.ID),
R2 AS(
SELECT ANY_VALUE(R1).*, ARRAY_AGG(( SELECT AS STRUCT Table3.* EXCEPT(ID))) AS Table3
FROM R1 LEFT JOIN Table3 USING(ID)
GROUP BY R1.ID),
...
SELECT ANY_VALUE(R9).*, ARRAY_AGG(( SELECT AS STRUCT Table10.* EXCEPT(ID))) AS Table10
FROM R9 LEFT JOIN Table10 USING(ID)
The thing is that for example in my first table I can have two records with the same ID but some other fields will be different and I want to consider them as two distinct records and thus group by all the fields of the table while I join.
Then I want to do the same with all the "sub-table" (the R tables in the query), so I will able to group by all the fields of the nested tables.
How can I do it easily ?
I tried GROUP BY Table1.* but it doesn't work...
Thank you in advance
Try to_json_string:
...
FROM Table1 t1
...
GROUP BY to_json_string(t1)
You seem to want something like this:
select *
from table1 t1 left join
(select t2.*
from table2 t2
where true
qualify row_number() over (partition by t2.id order by t2.id) = 0
) t2
using (id)
This uses qualify instead of group by to fetch one row.
If you don't want all rows from from table1, you can whittle them down as well:
select *
from (select t1.*
from table1 t1
where true
qualify row_number() over (partition by id, col1, col2 order by id) = 1
) t1 left join
(select t2.*
from table2 t2
where true
qualify row_number() over (partition by t2.id order by t2.id) = 0
) t2
using (id)
How to Group By all fields ...?
I tried GROUP BY Table1.* but it doesn't work...
Consider below example
SELECT ANY_VALUE(t1).*,
ARRAY_AGG(( SELECT AS STRUCT t2.* EXCEPT(ID))) AS Table2
FROM Table1 t1 LEFT JOIN Table2 t2 USING(ID)
GROUP BY FORMAT('%t', t1)
I have two table which I would like to union. I need to keep only the duplicates from one of the two tables. I tried to find it, but could not find it anywhere. Hope somebody can help.
For example:
Table_1:
ID
Product
Amount
1
A
10
2
B
10
3
C
10
Table_2:
ID
Product
Amount
3
C
9
4
A
100
5
B
100
Desired result:
ID
Product
Amount
1
A
10
2
B
10
3
C
9
4
A
100
5
B
100
So always use the duplicates from table_2. In this example ID 3 is duplicate, so use the duplicate of table_2 with amount 9.
How to realize this with T-SQL? I used the code below:
Select * from Table_1 where Table_1.id != Table_2.id
Union All
Select * from Table_2
But then I receive the error:
'The multi-part identifier "Table_2.ID" could not be bound.'
Use not exists:
Select t1.*
from Table_1 t1
where not exists (select 1 from table_2 t2 where t2.id = t1.id)
Union All
Select t2.*
from Table_2 t2;
Try this:
SELECT T1.*
FROM #Table1 T1
WHERE T1.ID NOT IN (SELECT ID FROM #Table2)
UNION
SELECT T2.*
FROM #Table2 T2
I assume what you want is an EXISTS:
SELECT T1.ID,
T1.Product,
T1.Amount
FROM dbo.Table1 T1
WHERE NOT EXISTS (SELECT 1
FROM dbo.Table2 T2
WHERE T1.ID = T2.ID)
UNION ALL
SELECT T2.ID,
T2.Product,
T2.Amount
FROM dbo.Table2 T2;
A FULL OUTER JOIN, however, might also work if ID is unique in both tables:
SELECT ISNULL(T2.ID,T1.ID) AS ID,
ISNULL(T2.Product,T1.Product) AS Product,
ISNULL(T2.Amount,T1.Amount) AS Amount
FROM dbo.Table1 T1
FULL OUTER JOIN dbo.Table2 T2 ON T1.ID = T2.ID;
Union will give you the result. Union will always return unique values always. If you use union all you will get all with duplicates. Your answer would be to use union all.
SELECT
B.ID
,B.Product
,B.Amount
FROM
(
SELECT
A.ID
,A.Product
,A.Amount
,ROW_NUMBER() over (Partition BY ID, Product order by Amount ASC) AS [row_num]
FROM
(
SELECT
tb_1.*
FROM tb_1
UNION ALL
SELECT
tb_2.*
FROM tb_2
) AS A
) AS B
WHERE B.[row_num] = 1
i want to count sum of this after minus please help me
SELECT t1.*
FROM table1 t1
MINUS
SELECT t2.*
FROM table2 t1
JOIN customers c ON t1.number = t2.number;
Another way is using CTE
With cte as (SELECT t1.*
FROM table1 t1
MINUS
SELECT t2.*
FROM table2 t1
JOIN customers c ON t1.number = t2.number)
Select count(*) from cte;
one way is :
select count(*) from (
SELECT *
FROM table1 t1
MINUS
SELECT *
FROM table2 t1
JOIN customers c ON t1.number = t2.number
) t
I suspect that you really want:
select count(*)
from (select number
from table1
minus
select number
from customers
) t;
It seems really odd that you would have two tables (table1 and table2 in your question) with exactly the same columns.
In addition, this does something useful, which is to count the number of numbers in table1 that are not customers.
I have a table:
My select:
select regexp_split_to_table(t3."Id"::character varying,'') as s
from (select t1."Id" from table1 t1
union all
select t2."Id"from table2 t2) t3
order by s
Or also I can get a string '22173345566179111134546175622323811' with this:
select string_agg(t3."Id"::character varying,'') as s
from (select t1."Id" from table1 t1
union all
select t2."Id"from table2 t2) t3
I need to get a table with number|count data, I mean for any number to get a count of repetitions in the select, for example:
1 | 9
2 | 5
3 | 5
and so on..
PostgreSQL DBMS
Does this do what you want?
select id, count(*)
from (select t1."Id" from table1 t1
union all
select t2."Id" from table2 t2
) t3
group by id
order by id;
If I understand you right, you want a list of all digits, that exist in a set of IDs from two tables and the count of each digit, how often it appears in all these IDs. If so, you just need to GROUP BY a digit and use count().
SELECT s.d,
count(*) count
FROM (SELECT t1."Id"
FROM table1 t1
UNION ALL
SELECT t2."Id"
FROM table2 t2) t3
CROSS JOIN LATERAL regexp_split_to_table(t3."Id"::character varying, '') s(d)
GROUP BY s.d
ORDER BY s.d;
easiest way
select regexp_split_to_table(t3."Id"::character varying,'') s, count(*) count
from (select t1."Id" from table1 t1 union all select t2."Id"from table2 t2) t3
group by s
I've two related tables:
Table1
Id
-----
1
2
3
Table2
Id Feature
--------------
1 Car
1 Moto
1 Camper
2 Moto
2 Scooter
3 Apple
I want to select Ids which have, for example, both 'Car' AND 'Moto'.
So in the example i want to get only Id = 1.
Use the INTERSECT operator:
select id from table2 where feature = 'Car'
intersect
select id from table2 where feature = 'Moto'
This:
WITH features AS
(
SELECT feature
FROM (
VALUES
('Car'),
('Moto')
) q (feature)
)
SELECT *
FROM table1 t1
WHERE NOT EXISTS
(
SELECT feature
FROM features
EXCEPT
SELECT feature
FROM table2 t2
WHERE t2.id = t1.id
)
or this:
SELECT *
FROM table t1
WHERE (
SELECT COUNT(*)
FROM table2 t2
WHERE t2.id = t1.id
AND t2.feature IN ('Car', 'Moto')
) = 2
Which query is more efficient depends on how many records you have in both tables and how many matches there are.
This select does two LEFT OUTER JOINs to table2 (one based on 'Car' and the other based on 'Moto') and makes sure that each JOIN returned a result. The DISTINCT ensures that you get each ID only once.
SELECT DISTINCT t1.id
FROM table2 t2
LEFT OUTER JOIN table2 t2_2 ON t2.id = t2_2.id AND t2_2.feature = 'Moto'
WHERE t2.feature = 'Car'
AND t2_2.id IS NOT NULL
Edit: Removed join to table1 since it really isn't needed.