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
Related
I'm trying to remove duplicates on a column in SQL, without including that column in the extract (since it contains personally identifiable data). I thought I might be able to do this with nested queries (as below), however this isn't working. I also thought it might be possible to remove duplicates in the WHERE statement, but couldn't find anything from googling. Any ideas? Thanks in advance.
SELECT [ETHNIC], [RELIGION]
FROM
(SELECT DISTINCT [ID], [ETHNIC], [RELIGION]
FROM MainData)
Using distinct like that will apply distinct to the row, so if there are two rows with the same ID but different ETHNIC and RELIGION the distinct won't remove them. To do that you could use group by in your query, but then you need to use an aggregation (e.g. max):
SELECT [ETHNIC], [RELIGION]
FROM
(SELECT [ID], MAX([ETHNIC]) AS ETHNIC, MAX([RELIGION]) AS RELIGION
FROM MainData
GROUP BY [ID])
If that's not what you're looking for, some SQL dialects require that you name your inner select, so you could try adding AS X to the end of your query.
I have finally succeeded in summing the results of two sql sum queries. One small step for this guy:)
My question relates to the last character in the code (Z):
SELECT SUM(hr)
FROM (SELECT SUM(amount) AS hr
FROM Try_again.dbo.tuesday_practice_database
WHERE account_name LIKE 'concessions'
UNION
SELECT SUM(amount) AS hr
FROM Try_again.dbo.tuesday_practice_database
WHERE account_name LIKE 'salaries')Z
The code won't work unless there is something following the closing parenthesis).
I'm just curious why that is and why does there need to be a character following the ).
It seems that it doesn't matter what the character is, the code will work. But the code breaks if I leave it blank.
Thank you
SELECT sum(hr)
FROM
(
Select sum(amount) as hr
from Try_again.dbo.tuesday_practice_database
where account_name like 'concessions'
union
Select sum(amount) as hr
from Try_again.dbo.tuesday_practice_database
where account_name like 'salaries'
) z
To understand better, look at the above version of your query. It's the same code, just reformatted to help illustrate what is happening. If you notice, the parent FROM clause retrieves data from a sub-query. In this context, SQL requires the subquery to have a name of some kind, and so the z is added as an alias to meet that requirement. You could put anything you wanted there, but since the name doesn't matter to us a single-letter placeholder is fine.
Just like the following query :
select * from table1 as z
By the way, you didn't use wildcard in your LIKE clause! I think you should re-write the query like below :
select sum(hr) from
(
Select sum(amount) as hr from Try_again.dbo.tuesday_practice_database
where account_name like '%concessions&'
union all
Select sum(amount) as hr from Try_again.dbo.tuesday_practice_database
where account_name like '%salaries%'
) AS z
If you don't want to use wildcard, then you should avoid using LIKE Use IN instead and re-write to this simple one :
Select sum(amount) from Try_again.dbo.tuesday_practice_database
where account_name in('concessions', 'salaries')
Just do this:
SELECT SUM(amount) as hr
FROM Try_again.dbo.tuesday_practice_database
WHERE account_name IN ('concessions', 'salaries')
The existing code has a bug, where it will consolidate your two SUM()s if they are both the same amount. You could also fix this with UNION ALL instead of just UNION, but since the LIKE conditions don't have any placeholders like % or _ we can do better and simplify this whole thing down to just one IN() condition, with no need for any subqueries.
Now, if you wanted to allow more variance in your matches ( ie LIKE '%concessions%' and LIKE '%salaries%'), then the UNION ALL is more helpful... just be warned that leading % placeholders in a LIKE condition are very bad for performance, and should be avoided when possible. Often this means changing the schema in some way, such as adding a table named something like AccountCategories that group each account into a specific category that you can target exactly in your query.
But all of that side-steps the actual question: what is that z character?
In this case, it's an alias. You're using a subquery to union the two smaller queries together. In certain contexts, the SQL language requires subqueries to have a name. This includes using the subquery (derived table) as the target of a FROM, JOIN, or APPLY expression. You can use any name you want — it doesn't matter to the functioning of the query, since it's never referenced again — and so a simple single-letter placeholder, like z, is good enough.
Given a relation R with n columns. Use sql to returns the tuples having the maximum number of occurrences of the values. I have no idea how to do query horizontally?
SELECT MAX(t.*) FROM mytable t
or
SELECT DISTINCT a, b, c FROM mytable
or
SELECT DISTINCT * FROM mytable
it depends on which SQL implementation you are referring to, and generally more information about the query. but the above examples should get you started so you can google some terms.
I'm not sure what you mean by querying horizontally. Is it one relation with multiple key columns linking the two tables? Sounds like you might just need to group by those columns and order by count(*) descending...
You cannot (should not) put non-aggregates in the SELECT line of a GROUP BY query.
I would however like access the one of the non-aggregates associated with the max. In plain english, I want a table with the oldest id of each kind.
CREATE TABLE stuff (
id int,
kind int,
age int
);
This query gives me the information I'm after:
SELECT kind, MAX(age)
FROM stuff
GROUP BY kind;
But it's not in the most useful form. I really want the id associated with each row so I can use it in later queries.
I'm looking for something like this:
SELECT id, kind, MAX(age)
FROM stuff
GROUP BY kind;
That outputs this:
SELECT stuff.*
FROM
stuff,
( SELECT kind, MAX(age)
FROM stuff
GROUP BY kind) maxes
WHERE
stuff.kind = maxes.kind AND
stuff.age = maxes.age
It really seems like there should be a way to get this information without needing to join. I just need the SQL engine to remember the other columns when it's calculating the max.
You can't get the Id of the row that MAX found, because there might not be only one id with the maximum age.
You cannot (should not) put non-aggregates in the SELECT line of a GROUP BY query.
You can, and have to, define what you are grouping by for the aggregate function to return the correct result.
MySQL (and SQLite) decided in their infinite wisdom that they would go against spec, and allow queries to accept GROUP BY clauses missing columns quoted in the SELECT - it effectively makes these queries not portable.
It really seems like there should be a way to get this information without needing to join.
Without access to the analytic/ranking/windowing functions that MySQL doesn't support, the self join to a derived table/inline view is the most portable means of getting the result you desire.
I think it's tempting indeed to ask the system to solve the problem in one pass rather than having to do the job twice (find the max, and the find the corresponding id). You can do using CONCAT (as suggested in Naktibalda refered article), not sure that would be more effeciant
SELECT MAX( CONCAT( LPAD(age, 10, '0'), '-', id)
FROM STUFF1
GROUP BY kind;
Should work, you have to split the answer to get the age and the id.
(That's really ugly though)
In recent databases you can use sum() over (parition by ...) to solve this problem:
select id, kind, age as max_age from (
select id, kind, age, max(age) over (partition by kind) as mage
from table)
where age = mage
This can then be single pass
PostgesSQL's DISTINCT ON will be useful here.
SELECT DISTINCT ON (kind) kind, id, age
FROM stuff
ORDER BY kind, age DESC;
This groups by kind and returns the first row in the ordered format. As we have ordered by age in descending order, we will get the row with max age for kind.
P.S. columns in DISTINCT ON should appear first in order by
You have to have a join because the aggregate function max retrieves many rows and chooses the max.
So you need a join to choose the one that the agregate function has found.
To put it a different way how would you expect the query to behave if you replaced max with sum?
An inner join might be more efficient than your sub query though.
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.