SQL Getting Data with extra row - sql

I have two tables with columns of my interests as Table1.Column1 and Table2.Column2
Table1 is Kind of a Group Table and Table2 is items table. The join query of these two tables gets the data in the followinf format
Column1 Column2
A 1
A 2
B 1
B 2
B 3
What I want is to get data in the following format:
Column1 Column2
A 0
A 1
A 2
B 0
B 1
B 2
B 3
i.e. getting extra 0 for each group at the start each time. The 0 does not exits in the database.
Does anyone know how to achive this in SQL?
Many Thanks,

This is one way to do it.
SELECT DISTINCT Column1, [Column2] = 0
FROM (
YourOriginalQuery
) q
UNION ALL
YourOriginalQuery
Most likely, there are better solutions by incorporating this requirement into your original query. If you post your query, we can come up with better alternatives.

Or something like:
select C.CategoryId, drv.CategoryGroupId from Category as C
cross join (
select 0 as CategoryGroupId
UNION
select CG.CategoryGroupId from CategoryGroup as CG
)drv order by CategoryId, CategoryGroupId

Related

Exclude one item with different corelated value in the next column SQL

I have two tables:
acc_num
ser_code
1
A
1
B
1
C
2
C
2
D
and the second one is:
ser_code
value
A
5
B
8
C
10
D
15
I want to exclude all the accounts with the service codes that they have value of 10 or 15.
Because my data set is huge, I want to use NOT EXIST but it just excludes combination of acc_num and ser_code.
I want to exclude the acc_num with all of it's ser_code, because on of it's ser_code meats my criteria.
I used:
select acc_num, ser_code
from table 1
where NOT EXIST (select 1
FROM table 2 where acc_num = acc_num and value in (10, 15)
out put with above code is:
acc_num
ser_code
1
A
1
B
Desire out put would be empty.
here you are
select t1.acc_num,t1.ser_code from table1 t1, table2 t2
where (t1.ser_code=t2.ser_code and t2.value not in (10,15))
and t1.acc_num not in
(
select t3.acc_num from table1 t3,table2 t4
where t1.acc_num=t3.acc_num and t3.ser_code=t4.ser_code
and t4.value in (10,15)
) ;
This could be achieved in many ways. However using NOT EXISTS is the best option. The problem with your query is for acc_num 1, there are ser_code that does not have value as 10, 15. So you will get A and B in result.
To overcome that you must pull acc_num inside the sub-query
Query 1 (using NOT EXISTS):
As you can see in the below query, I have included acc_num inside sub-query, so that the filter works properly,
SELECT DISTINCT a.acc_num, a.ser_code
FROM one as a
WHERE NOT EXISTS
(
SELECT DISTINCT one.acc_num
FROM two
INNER JOIN one
ON one.ser_code=two.ser_code
WHERE value IN (10,15) AND a.acc_num=one.acc_num
)
Query 2 (using LEFT JOIN):
NOT EXISTS often confusing due to it's nature (super fast though). Hence LEFT JOIN could also be used (expensive than NOT EXISTS),
SELECT DISTINCT a.acc_num, a.ser_code
FROM one as a
LEFT JOIN
(
SELECT DISTINCT one.acc_num
FROM two
INNER JOIN one
ON one.ser_code=two.ser_code
WHERE value IN (10,15)
) b
ON a.acc_num=b.acc_num
WHERE b.acc_num IS NULL
Query 3 (using NOT IN):
NOT IN would also achieve this with comprehensive query but expensive than both of the above methods,
SELECT DISTINCT a.acc_num, a.ser_code
FROM one as a
WHERE a.acc_num NOT IN
(
SELECT DISTINCT one.acc_num
FROM two
INNER JOIN one
ON one.ser_code=two.ser_code
WHERE value IN (10,15)
)
All 3 would yield same result. I would prefer to go with NOT EXISTS
See demo with time consumption in db<>fiddle

A left outer join on table that may or may not exist - can i avoid job failure?

I'm looking to do a join like
select
a.*,
b.info
from
[table_a] a
left outer join
[table_b_20160510] b
on
a.id=b.id
[table_b_yyyymmdd] is a log table that may or may not exist and i can't know in advance.
Is there a way to formulate this query such that it wont fail if an individual log table for a particular date does not happen to exist?
I know i can do a table date range function but it could even end up that a reasonable range of days might be missing logs (primarily historical from before we started capturing them).
My solution is to make a big table_b that has everything and a log date then subselect out the date range of interest so if that returns 0 rows then no problem. It's just that my big table_b of all the logs will get crazy big before long so this approach seems a bit inefficient.
I also tried table_query() here to see if maybe that would fail gracefully but it throws an error (which of course makes sense).
select
*
from
(select 'test' as id) a
left outer join
(select * from TABLE_QUERY(misc,'table_id CONTAINS "FOO_THIS_TABLE_DOES_NOT_EXIST"')) b
on
a.id=b.id
This is what I could do
Assume below is your table_b_20160510:
SELECT * FROM temp.table_b_20160510
Row id info
1 1 abc
2 2 xyz
I would create empty table with exactly same schema and zero rows - table_b_empty
SELECT * FROM temp.table_b_empty
Row id info
Query returned zero records.
So, now consider below query:
SELECT a.*, b.info
FROM
(SELECT * FROM (SELECT 1 AS id), (SELECT 2 AS id), (SELECT 3 AS id)) a
LEFT JOIN
(SELECT * FROM TABLE_QUERY
(temp, 'table_id = "table_b_20160510" OR table_id = "table_b_empty"')
) b
ON a.id=b.id
Table - table_b_20160510 - exists, so result is:
Row a_id b_info
1 1 abc
2 2 xyz
3 3 null
Now, try with table_b_20160511 (assuming it does not exist)
SELECT a.*, b.info
FROM
(SELECT * FROM (SELECT 1 AS id), (SELECT 2 AS id), (SELECT 3 AS id)) a
LEFT JOIN
(SELECT * FROM TABLE_QUERY
(temp, 'table_id = "table_b_20160511" OR table_id = "table_b_empty"')
) b
ON a.id=b.id
No failure and result is:
Row a_id b_info
1 1 null
2 2 null
3 3 null
Hope you can adopt this idea to your particular case

Using Postgres: Create a Column of Binary Data Conditional on Data in Another Table

I have a table with a list of unique ID's and columns of data describing characteristics of those ID's. It takes the form:
ID Tall Funny Weight
1 1 0 200
2 0 0 180
3 1 1 250
and so on. I have another table which is simply a list of ID's of people who have a characteristic, such as income over 100k.
Rich
1
3
What I would like to do is create a column in the first table that = 1 if they are in the second table and 0 otherwise. I can do this in R like this:
TableA$Rich <- TableA$ID %in% TableB
but it's incredibly slow, if for no other reason because my postgres (ParAccel/PaDB) cluster has more resources than where I can run R. Can you help me accomplish this?
I tried doing a left outer join, like...
create table c as(select a.id, tall, funny, weight,b.id as rich
from tablea a
left outer join tableb b
on a.id = b.id);
but it produced unexpected results. It gives me
ID Tall Funny Weight Rich
1 1 0 200 1
2 0 0 180 2
3 1 1 250 3
even though it should be "1, NULL, 3" and I would also prefer 1's and 0's. I was concerned that it may be an error with the data, but the data looks correct. I tried the same thing with a case when statement and got the same results but with "TRUE" for all values of Rich.
A case statement solves your problem:
create table c as
select a.id, tall, funny, weight,
(case when b.id is null then 0 else 1 end) as rich
from tablea a left outer join
tableb b
on a.id = b.id;
select
a.id, tall, funny, weight,
(b.id is not null)::integer as rich
from
tablea a
left outer join
tableb b on a.id = b.id

Select from two tables which have no relation

I don't know if it is possible or not. If possible, please help me to resolve this.
I have two tables, table1 and table2:
table1 table2
column1 column2 column3 column4
1 2 A B
3 4 C D
There is no relation between table1 and table2. I want to execute a query so that my output looks like this:
Output table:
column1 column2 column3 column4
1 2 A B
1 2 C D
3 4 A B
3 4 C D
Can anyone please tell me how can I achieve this? We are using SQL Server 2005.
Thanks,
Kartic
This is called a cross join, which produces a Cartesian product of all the records in each of the tables. The best way to do this is explicitly, with the cross join syntax:
select t1.*, t2.*
from table1 t1 cross join
table2 t2;
Note that if either table is empty, then you will not get any rows back.
You need to use cross join.
select t1.*,t2.* from table1 t1
Cross Join table2 t2;
Like this?
SELECT * FROM table1 CROSS JOIN table2
It's called a cross join, or cartesian product.
You can add additional filtering or join conditions using WHERE.

View over multiple tables containing same columns

I have four tables containing exactly the same columns, and want to create a view over all four so I can query them together.
Is this possible?
(for tedious reasons I cannot/am not permitted to combine them, which would make this irrelevant!)
Assuming that in addition to having the same column names, columns of the same contain the same data, you want to create a view that is the union of all those tables.
Something like the following should work, but my SQL is rusty:
(CREATE VIEW view_name AS
(SELECT * FROM table1
UNION
SELECT * FROM table2
UNION
SELECT * FROM table3));
It may be worth noting that you might need to use "union all" to preserve unique rows which may exist in more than one of the tables. A standard union will remove duplicates.
It is difficult to tell from your query whether you expect the data to be returned based on a UNION, or as a view containing the columns discretely. This obviously has an effect.
Consider the following sample:
TableA
ID Name RelatedID
1 John 2
2 Paul 1
TableB
ID Name RelatedID
1 Ringo 1
2 George 1
TableC
ID Name RelatedID
1 Bob 1
TableD
ID Name RelatedID
1 Kate NULL
Now, run the following query against this:
SELECT ID, Name FROM TableA
UNION ALL
SELECT ID, Name FROM TableB
UNION ALL
SELECT ID, Name FROM TableC
UNION ALL
SELECT ID, Name FROM TableD
This results in the following output:
1 John
2 Paul
1 Ringo
2 George
1 Bob
1 Kate
Is this what you are after? If so, you use a UNION query.
Now, if the effect you are after is to have a discrete view of related data, you may need to do something like this:
SELECT A.ID MasterID, A.Name MasterName,
B.ID BandID, B.Name BandName,
C.ID BlackadderID, C.Name BlackadderName
D.ID BlackadderRealID, D.Name BlackadderRealName
FROM
TableA A
INNER JOIN
TableB B
ON
A.RelatedID = B.ID
INNER JOIN
TableC C
ON
B.RelatedID = C.ID
INNER JOIN
TableD D
ON
C.RelatedID = D.ID
This will result in the following view of the data:
MasterID MasterName BandID BandName BlackAdderID BlackAdderName BlackadderRealID BlackadderRealName
1 John 2 George 1 Bob 1 Kate
2 Paul 1 Ringo 1 Bob 1 Kate
Use union.
Here is explanation
Use the union statement
select * from table1
union
select * from table2
union
select * from table3
You can if you union them (I would suggest including some indicator as to which table each record came from):
select table1.column1, 1 as TableNumber
from table1
union
select table2.column1, 2 as TableNumber
from table2
.. etc ..
Rather than UNION, use UNION ALL, unless you specifically want duplicate rows to be excluded. UNION on its own takes longer to execute (because of the sort it does to find dupes), and removes duplicate rows.