General except query is like this
(SELECT * FROM name_of_table_one
EXCEPT
SELECT * FROM name_of_table_two);
is there a way to write a query where I pass a list of values and perform except or intersect operation with a specific column of a table and select from that the list I had passed to DB.
Use a VALUES list.
select * from (values (1),(2),(100000001)) as f (aid)
except
select aid from pgbench_accounts
You can achieve that with the IN clause
"except":
SELECT * FROM your_table WHERE your_column NOT IN (list of values)
"intersect":
SELECT * FROM your_table WHERE your_column IN (list of values)
Related
Let's start from data:
DECLARE #Avengers TABLE ([Hero] varchar(32), [Preference] varchar(32));
INSERT INTO #Avengers VALUES
('Captain_America','gingers'),('Captain_America','blondes'),
('Captain_America','brunettes'),('Hulk','gingers'),('Hulk','blondes'),
('Hawkeye','gingers'),('Hawkeye','brunettes'),('Iron_Man','blondes'),
('Iron_Man','brunettes'),('Thor','gingers'),('Nick_Fury','blondes');
Now I would like to pass a #Preferences as a list of [Preference] (either comma separated or single column table parameter) without knowing how many parameters I am going to get and based on this to select [Hero] who prefers exactly these #Preferences as provided in parameter (list), by that I mean if I am after 'blondes' and 'gingers' then I am after 'Hulk' only
(NOT 'Captain_America' who prefers 'blondes', 'gingers' and 'brunettes').
I would like to get something like:
SELECT [Hero]
FROM #Avengers
WHERE *IS_ASSIGNED_ONLY_TO_THE_LIST*([Preference]) = #Preference
Well, I think I overcomplicated my code, but it works.
SELECT a.Hero, COUNT(*), MIN(p.N)
FROM #Avengers a
LEFT JOIN ( SELECT *, COUNT(*) OVER() N
FROM #Preferences) p
ON a.Preference = p.Preference
GROUP BY a.Hero
HAVING COUNT(*) = MIN(p.N)
AND COUNT(*) = COUNT(p.Preference)
;
I'm using #Preferences as a table.
I have a recursive query in which i m getting rows of arrays as shown below. How could I possible merge all rows into one array in one row and removing duplicates? Ordering is not important.
--my_column--
"{431}"
"{431,33}"
"{431,60}"
"{431,28}"
"{431,1}"
"{431,226}"
"{431,38}"
"{431,226,229}"
"{431,226,227}"
"{431,226,235}"
"{431,226,239}"
"{431,226,241}"
I tried the query below but I am getting one empty integer [] column
select array(select unnest(my_column) from my_table
thanks
Use array_agg() with distinct and (not necessary) order by from unnest():
with my_table(my_column) as (
values
('{431}'::int[]),
('{431,33}'),
('{431,60}'),
('{431,28}'),
('{431,1}'),
('{431,226}'),
('{431,38}'),
('{431,226,229}'),
('{431,226,227}'),
('{431,226,235}'),
('{431,226,239}'),
('{431,226,241}')
)
select array_agg(distinct elem order by elem)
from my_table,
lateral unnest(my_column) elem;
array_agg
---------------------------------------------
{1,28,33,38,60,226,227,229,235,239,241,431}
(1 row)
Another solution without lateral subquery:
select array_agg(distinct val) from
(select unnest(my_column) as val from my_table) x;
I have field with values for instance:
323.12.444.1
55.1231
4543.432.431
6.1
456.3234.54353.1124.1
321.3.425
2.3.1
5345.43.1
432.5646.2
So for records ended by .1 has to be gathered. What should be the query?
This should be faster than LIKE
SELECT * FROM table WHERE RIGHT(fieldname,2)='.1'
The LIKE with a % at the beginning is something one should avoid if possible...
select * from table where fieldname like '%.1'
I would suggest to use this:
SELECT *
FROM YourTable
WHERE REVERSE(SUBSTRING(REVERSE(col1),1,CHARINDEX('.',REVERSE(col1))-1)) = '1'
You can find any string you need without changing parameters inside query:
;WITH YourTable AS (
SELECT *
FROM (VALUES
('323.12.444.1'),
('55.1231'),
('4543.432.431'),
('6.1'),
('456.3234.54353.1124.1'),
('321.3.425'),
('2.3.1'),
('5345.43.1'),
('432.5646.2')
) as t(col1)
)
SELECT *
FROM YourTable
WHERE REVERSE(SUBSTRING(REVERSE(col1),1,CHARINDEX('.',REVERSE(col1))-1)) = '431'
Output:
4543.432.431
Ive got two tables. One has 102845 records, the other has 98496. I need to find the records that appear in the bigger table but not in the smaller table (4349).
These are how I create the numbers:
--98496
drop table #test2
select a.*, B.Delq_Sep12, b.Bal_Sep12, b.Queue_Sep12
into #test2
from #test4 b
join pcd a on (a.ACCOUNT_NUMBER = B.account_number)
--102845
drop table #test1
select a.*, B.Delq_Sep12, b.Bal_Sep12, b.Queue_Sep12,
into #test1
from #test4 b
left join pcd a on (a.ACCOUNT_NUMBER = B.account_number)
Thanks
select * from #test1
except
select * from #test2
Of course, this assumes that all records in #test2 are in #test1
If you want to check the reverse, just reverse the query.
select * from #test2
except
select * from #test1
Apparently, your first query gets only matching rows from the two tables. The second one gets all rows from b while also pulling data from a where there is a match, and if there was no match, the a columns get filled with NULLs.
Now, the difference between the two result sets would effectively be the non-matching rows of b. And to get those rows, you could just use your second query with a NULL check like this:
select a.*, B.Delq_Sep12, b.Bal_Sep12, b.Queue_Sep12,
from #test4 b
left join pcd a on (a.ACCOUNT_NUMBER = B.account_number)
where a.ACCOUNT_NUMBER is null
That is, no #test1 or #test2 is needed, just query for the non-matching rows directly.
Is it possible to access a temporary column that was defined in a query for a Common Table Expression? Say I have
select * from myTable
;with cte as
(
select
*, Salary * 4 as FourTimesSalary
from
Employees
where
Name = #name
and ID >= 100
)
Is there a way to use the temporary column FourTimesSalary when querying cte like so?
select top 2 *
from cte
order by FourTimesSalary, Name
TIA.
Yes you can do that. Example:
with temp as
(
select 1 as id, 2*4 as val
UNION
select 2 as id, 3*4 as val
)
SELECT * FROM temp ORDER BY VAL desc
Your example looks fine, did you get an error when you tried that or something?