Union on two tables with a where clause in the one - sql

Currently I have 2 tables, both of the tables have the same structure and are going to be used in a web application. the two tables are production and temp. The temp table contains one additional column called [signed up]. Currently I generate a single list using two columns that are found in each table (recno and name). Using these two fields I'm able to support my web application search function. Now what I need to do is support limiting the amount of items that can be used in the search on the second table. the reason for this is become once a person is "signed up" a similar record is created in the production table and will have its own recno.
doing:
Select recno, name
from production
UNION ALL
Select recno, name
from temp
...will show me everyone. I have tried:
Select recno, name
from production
UNION ALL
Select recno, name
from temp
WHERE signup <> 'Y'
But this returns nothing? Can anyone help?

For what you are asking, you could do it this style.
SELECT * FROM
(
SELECT '1' as `col`
UNION
SELECT '2' as `col`
) as `someAlias`
where `someAlias`.`col` = '1'
Put the entire union inside parenthesis, give it an alias, then give the condition.

Not sure if I'm understanding what you want exactly. If you create records in the production table once they have signed up from the temp table, and you only want people who haven't signed up...you don't need to look in the production table at all. Simply:
SELECT recno, name FROM temp WHERE signup='N'
Or however you're trying to limit your search. If for some reason you do need a union but you're trying to eliminate duplicates you'd have to modify your statement to remove the ALL clause. Union ALL causes you to get duplicates. If you don't want duplicate values, you want to not use ALL in your UNION. You can read up on Unions here.

Related

Query for selecting same or similar data from different tables

I have doc_no, I need to find out its type. So I need to select a query from the table.
SELECT o.type_id
FROM operation_out o
WHERE o.doc_no = 17025337;
But what to do, if I have 3 different tables
operation_out, operation_in, operation_reverse
and given doc_no can be in any of the given tables.
I have already tried union:
SELECT transfer_type_id
FROM (SELECT doc_no, mt_o.type_id
FROM mt_operation_out mt_o
UNION ALL
SELECT doc_no, mt_in.type_id
FROM mt_operation_in mt_in
UNION ALL
SELECT doc_no, mt_r.type_id
FROM mt_operation_reverse mt_r)
WHERE doc_no = 17025337;
Is there another alternative way of writing this? Is there any syntax in SQL for this kind of task?
Thank you all for your recommendations. In the end, I created a view based on the UNION ALL, and I'm going to use it wherever needed.

Can a View hold some data

I have created a View:
CREATE VIEW Lunch
AS
SELECT 'Beer' AS item
UNION SELECT 'Olives'
UNION SELECT 'Bread'
UNION SELECT 'Salami'
UNION SELECT 'Calamari'
UNION SELECT 'Coffee';
GO
Then I executed the following query in a different query.
SELECT item FROM Lunch
This is resulting in the data from the view being returned. There are not any underlying tables to hold data. But still the system is showing records. How is this possible?
I don't fully understand the question. The view is not "holding data", it is holding a query. The query statement has constants in it that are turned into a result set that can be used by other queries.
You can think of a query as substituting the text of the query directly into a statement. So, when you do:
select *
from lunch;
SQL really processes this as:
select *
from ( SELECT 'Beer' AS item
UNION SELECT 'Olives'
UNION SELECT 'Bread'
UNION SELECT 'Salami'
UNION SELECT 'Calamari'
UNION SELECT 'Coffee'
) t
This is a good model of what happens, although it is not quite what really happens. What really happens is that the view is compiled and the compiled code is inserted into the compiled code for the query.
There is another concept of "materialized views". These are views where you have indexes and the values are actually stored in the database. However, this is not an example of a materialized view.
It doesn't actually hold data, but it can evaluate SQL, which is all you're doing in the definition.
So the following can be evaluated:
SELECT 'Beer' AS item
UNION SELECT 'Olives'
UNION SELECT 'Bread'
UNION SELECT 'Salami'
UNION SELECT 'Calamari'
UNION SELECT 'Coffee';
The same as a view defined with:
SELECT * FROM Customers
SQL View Reference:
A view can be thought of as either a virtual table or a stored query. The data accessible through a view is not stored in the database as a distinct object. What is stored in the database is a SELECT statement. The result set of the SELECT statement forms the virtual table returned by the view. A user can use this virtual table by referencing the view name in Transact-SQL statements the same way a table is referenced.
A view is a Saved Select Statement in your case view definition does not have any underlying tables, but the select statement itself has hard coded (Constant) values.
Therefore it will always return this data.
Again to be clear it is not storing any data but the Select Statement which happens to return some constant values.
Yes, the data is shown because is statically included into the query itself.
I don't see anything uncommon here, the view refers to the query that embed the data .

SQL pattern to get "and" list of multiple-row matches?

I'm not a database programmer, but I have a simple database-backed app where I have items with tags. Each item may have multiple tags, so I'm using a typical junction table (like this), where each row represents the fact that the item with the appropriate ID has the tag with the appropriate ID.
This works very logically when I want to do something like select all items with a given tag.
But, what is the typical pattern for doing AND searches? That is, what if I want to find all items which have all of a certain set of tags? This is such a common operation that I'd think some of the intro tutorials would cover it, but I guess I'm not looking in the right places.
The approach I tried was to use INTERSECT, first directly and then with subqueries and IN. This works, but builds up long-seeming queries quickly as I add search terms. And, crucially, this approach appears to be about an order of magnitude slower than the approach of shoving all the tags as text into one "tags" column and using SQLite's full-text search. (And, as I would expect/hope, the FTS search gets faster as I add more terms, which doesn't seem to be the case with the INTERSECTS approach.)
What's the proper design pattern here, and what's the right way to make it snappy? I'm using SQLite in this case, but I'm most interested in a general answer, since this must be a common thing to do.
The following is the standard ANSI SQL solution which avoids synchronizing the number of ids and the ids themselves.
with tag_ids (tid) as (
values (1), (2)
)
select id
from tags
where id (select tid from tag_ids)
having count(*) = (select count(*) from tag_ids);
The values clause ("row constructor") is supported by PostgreSQL and DB2. For database that don't support that, you can replace it with a simple "select", e.g. in Oracle this would be:
with tag_ids (tid) as (
select 1 as tid from dual
union all
select 2 from dual
)
select id
from tags
where id (select tid from tag_ids)
having count(*) = (select count(*) from tag_ids);
For SQL Server you would simply leave out the "from dual", as it does not require a FROM clause for a SELECT.
This assumes that one tag can only be assigned exactly once. If that isn't the case, you would need to use a count(distinct id) in the having clause.
I would be inclined to use a group by:
select id
from tags
where id in (<tag1>, <tag2>)
group by id
having count(*) = 2
This would guarantee that both appear.
For an unlimited size list, you could store the ids in a string, such as '|tag1|tag2|tag3|' (note delimiters on ends). Then you can do:
select id
from tags
where #taglist like '%|'+tag+'|%'
group by id
having count(*) = len(#taglist) - (len(replace(#taglist, '|', '') - 1)
This is using SQL Server syntax. But, it is saying two things. The WHERE clause is saying that the tag is in the list. The HAVING clause is saying that the number of matches equals the length of the list. It does this with a trick, by counting the number of separtors and subtracting 1.

The used SELECT statements have a different number of columns

For examples I don't know how many rows in each table are and I try to do like this:
SELECT * FROM members
UNION
SELECT * FROM inventory
What can I put to the second SELECT instead of * to remove this error without adding NULL's?
Put the columns names explicitly rather than *, and make sure the number of columns and data types match for the same column in each select.
Update:
I really don't think you want to be UNIONing those tables, based on the tables names. They don't seem to contain related data. If you post your schema and describe what you are trying to achieve it is likely we can provide better help.
you could do
SELECT *
from members
UNION
SELECT inventory.*, 'dummy1' AS membersCol1, 'dummy2' AS membersCol2
from inventory;
Where membersCol1, membersCol12, etc... are the names of columns from members that are not in inventory. That way both queries in the union will have the same columns (Assuming that all the columns in inventory are the same as in members which seems very strange to me... but hey, it's your schema).
UPDATE:
As HLGEM pointed out, this will only work if inventory has columns with the same names as members, and in the same order. Naming all the columns explicitly is the best idea, but since I don't know the names I can't exactly do that. If I did, it might look something like this:
SELECT id, name, member_role, member_type
from members
UNION
SELECT id, name, '(dummy for union)' AS member_role, '(dummy for union)' AS member_type
from inventory;
I don't like using NULL for dummy values because then it's not always clear which part of the union a record came from - using 'dummy' makes it clear that the record is from the part of the union that didn't have that record (though sometimes this might not matter). The very idea of unioning these two tables seems very strange to me because I very much doubt they'd have more than 1 or 2 columns with the same name, but you asked the question in such a way that I imagine in your scenario this somehow makes sense.
Are you sure you don't want a join instead? It is unlikely that UNOIN will give you what you want given the table names.
Try this
(SELECT * FROM members) ;
(SELECT * FROM inventory);
Just add semicolons after both the select statements and don't use union or anything else. This solved my error.
I don't know how many rows in each table
Are you sure this isn't what you want?
SELECT 'members' AS TableName, Count(*) AS Cnt FROM members
UNION ALL
SELECT 'inventory', Count(*) FROM inventory
Each SELECT statement within the MySQL UNION ALL operator must have the same number of fields in the result sets with similar data types
Visit https://www.techonthenet.com/mysql/union_all.php

SQL select from data in query where this data is not already in the database?

I want to check my database for records that I already have recorded before making a web service call.
Here is what I imagine the query to look like, I just can't seem to figure out the syntax.
SELECT *
FROM (1,2,3,4) as temp_table
WHERE temp_table.id
LEFT JOIN table ON id IS NULL
Is there a way to do this? What is a query like this called?
I want to pass in a list of id's to mysql and i want it to spit out the id's that are not already in the database?
Use:
SELECT x.id
FROM (SELECT #param_1 AS id
FROM DUAL
UNION ALL
SELECT #param_2
FROM DUAL
UNION ALL
SELECT #param_3
FROM DUAL
UNION ALL
SELECT #param_4
FROM DUAL) x
LEFT JOIN TABLE t ON t.id = x.id
WHERE x.id IS NULL
If you need to support a varying number of parameters, you can either use:
a temporary table to populate & join to
MySQL's Prepared Statements to dynamically construct the UNION ALL statement
To confirm I've understood correctly, you want to pass in a list of numbers and see which of those numbers isn't present in the existing table? In effect:
SELECT Item
FROM IDList I
LEFT JOIN TABLE T ON I.Item=T.ID
WHERE T.ID IS NULL
You look like you're OK with building this query on the fly, in which case you can do this with a numbers / tally table by changing the above into
SELECT Number
FROM (SELECT Number FROM Numbers WHERE Number IN (1,2,3,4)) I
LEFT JOIN TABLE T ON I.Number=T.ID
WHERE T.ID IS NULL
This is relatively prone to SQL Injection attacks though because of the way the query is being built. It'd be better if you could pass in '1,2,3,4' as a string and split it into sections to generate your numbers list to join against in a safer way - for an example of how to do that, see http://www.sqlteam.com/article/parsing-csv-values-into-multiple-rows
All of this presumes you've got a numbers / tally table in your database, but they're sufficiently useful in general that I'd strongly recommend you do.
SELECT * FROM table where id NOT IN (1,2,3,4)
I would probably just do:
SELECT id
FROM table
WHERE id IN (1,2,3,4);
And then process the list of results, removing any returned by the query from your list of "records to submit".
How about a nested query? This may work. If not, it may get you in the right direction.
SELECT * FROM table WHERE id NOT IN (
SELECT id FROM table WHERE 1
);