SQL Insert with sub-select and multiple rows - mysql

I have an existing documents table and a new permissions table. I want to create a script that will give all permissions to all of the existing documents. The documents_permissions table will need the document_id and permission_id (1,2,3). So for each document I will need to insert 3 rows. This is where I am at atm:
INSERT INTO `documents_permissions` (`document_id`, `permission_id`)
SELECT `id`, '1' FROM `documents`
but I'd need to repeat that for each permission. What is the best way to do this?

try this:
USe CROSS JOIN
INSERT INTO `documents_permissions` (`document_id`, `permission_id`)
select `id`,a.permissions
from(
select 1 as permissions union all
select 2 union all
select 3 )a
cross join
`documents` d

INSERT INTO `documents_permissions` (`document_id`, `permission_id`)
select id, pid from `documents`
cross join (select 1 as pid union select 2 union select 3)X

Related

Hive SQL: How to create flag occurrence while join with other table

I want to check whether my member from table A present in table B or not? Here is the problem is Both Table A and Table B has millions of records and table B have duplicate records. So that i cann't do left join. it takes hours to run.
Table A
Table B
Output
use this :
select member,
case when EXISTS (select 1 from TableB where TableB.member = tableA.member) then 1 else 0 end as Flag
from tableA
Not a very good solution but you can try this.
So, we use not in or not exists to get one set of data and then use in or exists to get another set. And then union them all together to get complete set.
select
a.* , 0 flag
from tableA a where member not in ( select member from tableB)
union all
select
a.* , 1 flag
from tableA a where member in ( select member from tableB)
The trick may be, you can run 2 separate SQL for this and will get perf benefit instead of union all.
Not exist will work same way but can give you better performance.
SELECT a.*, 0 flag
FROM tableA a
WHERE NOT EXISTS(
SELECT 1 FROM tableB b WHERE (a.member=b.member))
union all
SELECT a.*, 1 flag
FROM tableA a
WHERE EXISTS(
SELECT 1 FROM tableB b WHERE (a.member=b.member))

SQL query with repeated values in list

How to write a query correctly to get data without uniqueness?
I have list of ids, where ids are repeated.
Example: (1,1,1,2,3)
select *
from table
where id in (1,1,1,2,3);
returns only (1,2,3).
But I need to get with repeated entries.
Use a derived table and left join:
select t.*
from (select 1 as id union all select 1 union all select 1 union all select 2 union all select 3
) i left join
t
on t.id = i.id
The syntax for the derived table might vary depending on the database, but most support the above syntax.
That's not what WHERE statement is for, as it's only for filtering matching keys.
If you need to do that in this order, use sth like
select table.*
from (
select 1 as id
union select 1
union select 1
union select 2
union select 3
) myStaticKeys
join table using (id)

Find values missing in a column from a set (mysql)

I am using mysql.
I have a table that has a column id.
Let us say I have an input set of ids. I want to know which all ids are missing in the table.
If the set is "ida", "idb", "idc" and the table only contains "idb", then the returned value should be "ida", "idc".
Is this possible with a single sql query? If not, what is the most efficient way to execute this.
Note that I am not allowed to use stored procedure.
MySQL will only return rows that exist. To return missing rows you must have two tables.
The first table can be temporary (session/connection specific) so that multiple instances can run simultaneously.
create temporary table tmpMustExist (text id);
insert into tmpMustExist select "ida";
insert into tmpMustExist select "idb";
-- etc
select a.id from tmpMustExist as a
left join table b on b.id=a.id
where b.id is null; -- returns results from a table that are missing from b table.
Is this possible with a single sql query?
Well, yes it is. Let me work my way to that, first with a union all to combine the select statements.
create temporary table tmpMustExist (text id);
insert into tmpMustExist select "ida" union all select "idb" union all select "etc...";
select a.id from tmpMustExist as a left join table as b on b.id=a.id where b.id is null;
Note that I use union all which is a bit faster than union because it skips over deduplication.
You can use create table...select. I do this frequently and really like it. (It is a great way to copy a table as well, but it will drop indexes.)
create temporary table tmpMustExist as select "ida" union all select "idb" union all select "etc...";
select a.id from tmpMustExist as a left join table as b on b.id=a.id where b.id is null;
And finally you can use what's called a "derived" table to bring the whole thing into a single, portable select statement.
select a.id from (select "ida" union all select "idb" union all select "etc...") as a left join table as b on b.id=a.id where b.id is null;
Note: the as keyword is optional, but clarifies what I'm doing with a and b. I'm simply creating short names to be used in the join and select field lists
There's a trick. You can either create a table with expected values or you can use union of multiple select for each value.
Then you need to find all the values that are in the etalon, but not in the tested table.
CREATE TABLE IF NOT EXISTS `single` (
`id` varchar(10) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `single` (`id`) VALUES
('idb');
SELECT a.id FROM (
SELECT 'ida' as id
UNION
SELECT 'idb' as id
UNION
SELECT 'idc' AS id
) a WHERE a.id NOT IN (SELECT id FROM single)
//you can pass each set string to query
//pro-grammatically you can put quoted string
//columns must be utf8 collation
select * from
(SELECT 'ida' as col
union
SELECT 'idb' as col
union
SELECT 'idc' as col ) as setresult where col not in (SELECT value FROM `tbl`)

Insert multiple rows with default values without using union

I use this query to insert multiple rows into my table user.
insert into user
(select 'bbb', coalesce(max(subid),0)+1 from user where name = 'bbb')
union
(select 'ccc', coalesce(max(subid),0)+1 from user where name = 'ccc');
How can I achieve the same result in a single select query?
Not quite. The problem is what happens when the names are not in the table. You can do this:
insert into user(name, subid)
select n.name, coalesce(max(u.subid), 1)
from (select 'bbb' as name union all select 'ccc') n left join
user u
on u.name = n.name
group by u.name;
It still has a union (all) for constructing the names, but the calculation of subid is only expressed once.
When using insert it is a good idea to list the columns explicitly.

How to get row count of 2 different tables (and databases) in one query?

I got a database named accounts and account table inside of this database, Also I got the database named players and player table inside of this database.
How can I get a rows count of this two tables in one query?
I've tried this:
SELECT
SUM(`account`.`account`.`id`) AS 'accounts',
SUM(`player`.`player`) AS 'players';
But it doesn't work.
If you need exactly rows count (not sum), than do something like this:
select
(select count(*) from accounts.account) as count1,
(select count(*) from players.player) as count2
or
select count(*) as `count`,"account" as `table` from accounts.account
union all
select count(*) as `count`,"player" as `table` from players.player
A simple UNION operation on two select statements will do:
SELECT COUNT(*), 'Accounts' FROM Accounts.Account
UNION
SELECT COUNT(*), 'Players' FROM Players.Player
And you have to qualify each table with the database name since they're in separate databases.
Try:
SELECT
COUNT(`account`.`id`) AS 'accounts',
COUNT(`player`.`player`) AS 'players'
FROM
`account`,
`player`
SELECT COUNT(*)
FROM (
SELECT Id
FROM accounts.account
UNION ALL
SELECT player
FROM players.player ) AS BothTables
with Value (nbr, name ) as
(
select count(*) amount, 'AccountsCount' as ab from accounts..account
union all
select count(*) amount, 'PlayersCount' as ab from players..player
)
select *
from value as s
PIVOT(sum(nbr) for name in (AccountsCount, PlayersCount) ) as pvt