Is there any way to select some fields from BSID where the combination of BUKRS-KUNNR-DMBTR is greater than 1. I thought that the below select will work, but it doesn't.
SELECT bukrs kunnr dmbtr COUNT(*)
INTO TABLE git_double
FROM bsid
WHERE bukrs = '1000' AND
blart = 'WP' AND
budat IN s_budat AND
gjahr IN s_gjahr AND
count(*) > 1
GROUP BY bukrs kunnr dmbtr.
Is there any way to do this in 1 selection?
Thanks
Selections on aggregate functions like COUNT can be done inside the HAVING clause
SELECT bukrs kunnr dmbtr COUNT(*)
INTO TABLE git_double
FROM bsid
WHERE bukrs = '1000' AND
blart = 'WP' AND
budat IN s_budat AND
gjahr IN s_gjahr
GROUP BY bukrs kunnr dmbtr
HAVING COUNT(*) > 1. " <==== HAVING after GROUP BY
For information, from ABAP 7.40 SP05, you may also write it by using host variables:
SELECT bukrs, kunnr, dmbtr, COUNT(*) AS accd_count
INTO TABLE #DATA(git_double)
FROM bsid
WHERE bukrs = '1000' AND
blart = 'WP' AND
budat IN #s_budat AND
gjahr IN #s_gjahr
GROUP BY bukrs, kunnr, dmbtr
HAVING COUNT(*) > 1.
Related
Each entry has an ID (random string of numbers and letters), a Name (string), and a type (string "A" or "B").
Some entries share the same ID and Name, but have different types.
I'm trying to write a select statement that ignores entries of type B when there is an entry using the same ID of type A.
As far as I understand, DISTINCT wont work as it relies on the elements matching in all columns, and can not differentiate based on a column.
Here's one way...
with type_a as
(select distinct id, name, type
from table_name
where type = 'A'
),
type_b as
(select distinct id, name, type
from table_name
where type = 'B'
and id not in (select id from type_a)
)
select * from type_a
union
select * from type_b
Use NOT EXISTS:
select t.*
from tablename t
where t.type = 'A'
or not exists (select 1 from tablename where id = t.id and name = t.name and type = 'A')
If the name should not be involved in the condition, then use this:
or not exists (select 1 from tablename where id = t.id and type = 'A')
Or use RANK() window function:
select t.id, t.name, t.type
from (
select t.*
rank() over (partition by id, name order by case when type = 'A' then 1 else 2 end) rnk
from tablename
) t
where t.rnk = 1
Or remove name from partition if it is not relevant.
So I have a union of various queries representing various conditions in order to reach my end goal, which is a list of entries according to their priority. This priority is given according to the
My query is
select priority, priority_description, name_of_entry, id_of_entry from (
select 0 priority, 'text' priority_description, name_of_entry, id_of_entry from table_a where *conditions for priority 0*
union select 1 priority, 'text' priority_description, name_of_entry, id_of_entry from table_a where *conditions for priority 1*
union select 2 priority, 'text' priority_description, name_of_entry, id_of_entry from table_a, tableb where *conditions for priority 2*
union select 3 priority, 'text' priority_description, name_of_entry, id_of_entry from table_a, tablec where *conditions for priority 3*
) x
The numbers and text for 1st and 2nd columns are manually entered while the others are what I want to retrieve.
The intended result is to only show the entry with the least priority if it's replicated. In other words, if an entry fulfils multiple conditions, thus appearing in priority 2 and 3, I only want the record to be shown once with priority 2.
One idea would be for example to add another condition "and where not exists in (previous condition), however this might make everything way too slow since it would be repeating queries multiple times.
How to achieve this in a better way?
Here's another option:
SELECT priority, priority_description, name_of_entry, id_of_entry
FROM (
SELECT priority, priority_description, name_of_entry, id_of_entry,
ROW_NUMBER() OVER(
PARTITION BY id_of_entry -- Group rows by "id_of_entry"
ORDER BY priority -- Assign "ranking" based on lowest priority
) AS RowNum
FROM (
SELECT
CASE
WHEN <conditions for priority 0> THEN 0 -- Look for priority 0 first
WHEN <conditions for priority 1> THEN 1
WHEN <conditions for priority 2> THEN 2
WHEN <conditions for priority 3> THEN 3
END AS priority,
'text' AS priority_description,
name_of_entry,
id_of_entry
FROM table_a
) src
) src
WHERE RowNum = 1 -- Get single rows with lowest priority
This assumes the same id_of_entry value can have multiple rows with different priority conditions.
Also, how do you handle cases when there are multiple rows with the same id_of_entry and priority values? As written, the query won't discriminate with regards to which row to return.
You can use distinct on:
with q as (<your query here>)
select distinct on (id_entry) q.*
from q
order by id_entry, priority;
That said, you can probably just use a single case expression for this. It is a little complicated because you have two values. One method is something like this:
select v.priority,
(case when v.priority = 0 then 'text0'
when v.priority = 1 then 'text1'
when v.priority = 2 then 'text2'
when v.priority = 3 then 'text3'
end) as priority_description,
name_of_entry, id_of_entry
from table_a a cross join lateral
(values (case when *conditions for priority 0* then 0
when *conditions for priority 1* then 1
when *conditions for priority 2* then 2
when *conditions for priority 3* then 3
end)
) v(priority)
You can add in the
You only select from table_a, with conditions on table[abc],so you can rewrite into:
SELECT COALESCE(zero.priority,one.priority,two.priority,three.priority)
AS priority
, a.name_of_entry, a.id_of_entry
, ...
FROM table_a a
LEFT JOIN (
select 0 priority, id_of_entry
from table_a
where *conditions for priority 0*
) zero ON zero.id_of_entry = a.id_of_entry
LEFT JOIN (
select 1 priority, id_of_entry
from table_a
where *conditions for priority 1*
) one ON one.id_of_entry = a.id_of_entry
LEFT JOIN (
select 2 priority, id_of_entry
from table_a
WHERE EXISTS(
SELECT*FROM table_b WHERE [table_a,table_b]
AND *conditions for priority 2*)
) two ON two.id_of_entry = a.id_of_entry
LEFT JOIN (
select 3 priority, id_of_entry
from table_a
WHERE EXISTS(
SELECT*FROM table_c WHERE [table_a,table_c]
AND *conditions for priority 3*)
) three ON three.id_of_entry = a.id_of_entry
;
I have a problem where I need to get the last item across various tables in PostgreSQL.
The following code works and returns me the type of the latest update and when it was last updated.
The problem is, this query needs to be used as a subquery, so I want to select both the type and the last updated value from this query and PostgreSQL does not seem to like this... (Subquery must return only one column)
Any suggestions?
SELECT last.type, last.max FROM (
SELECT MAX(a.updated_at), 'a' AS type FROM table_a a WHERE a.ref = 5 UNION
SELECT MAX(b.updated_at), 'b' AS type FROM table_b b WHERE b.ref = 5
) AS last ORDER BY max LIMIT 1
Query is used like this inside of a CTE;
WITH sql_query as (
SELECT id, name, address, (...other columns),
last.type, last.max FROM (
SELECT MAX(a.updated_at), 'a' AS type FROM table_a a WHERE a.ref = 5 UNION
SELECT MAX(b.updated_at), 'b' AS type FROM table_b b WHERE b.ref = 5
) AS last ORDER BY max LIMIT 1
FROM table_c
WHERE table_c.fk_id = 1
)
The inherent problem is that SQL (all SQL not just Postgres) requires that a subquery used within a select clause can only return a single value. If you think about that restriction for a while it does makes sense. The select clause is returning rows and a certain number of columns, each row.column location is a single position within a grid. You can bend that rule a bit by putting concatenations into a single position (or a single "complex type" like a JSON value) but it remains a single position in that grid regardless.
Here however you do want 2 separate columns AND you need to return both columns from the same row, so instead of LIMIT 1 I suggest using ROW_NUMBER() instead to facilitate this:
WITH LastVals as (
SELECT type
, max_date
, row_number() over(order by max_date DESC) as rn
FROM (
SELECT MAX(a.updated_at) AS max_date, 'a' AS type FROM table_a a WHERE a.ref = 5
UNION ALL
SELECT MAX(b.updated_at) AS max_date, 'b' AS type FROM table_b b WHERE b.ref = 5
)
)
, sql_query as (
SELECT id
, name, address, (...other columns)
, (select type from lastVals where rn = 1) as last_type
, (select max_date from lastVals where rn = 1) as last_date
FROM table_c
WHERE table_c.fk_id = 1
)
----
By the way in your subquery you should use UNION ALL with type being a constant like 'a' or 'b' then even if MAX(a.updated_at) was identical for 2 or more tables, the rows would still be unique because of the difference in type. UNION will attempt to remove duplicate rows but here it just isn't going to help, so avoid that wasted effort by using UNION ALL.
----
For another way to skin this cat, consider using a LEFT JOIN instead
SELECT id
, name, address, (...other columns)
, lastVals.type
, LastVals.last_date
FROM table_c
WHERE table_c.fk_id = 1
LEFT JOIN (
SELECT type
, last_date
, row_number() over(order by last_date DESC) as rn
FROM (
SELECT MAX(a.updated_at) AS last_date, 'a' AS type FROM table_a a WHERE a.ref = 5
UNION ALL
SELECT MAX(b.updated_at) AS last_date, 'b' AS type FROM table_b b WHERE b.ref = 5
)
) LastVals ON LastVals.rn = 1
Lets say I have a table with a column named KEY.
I want to find all KEYs which are in the table exactly 3 times.
How can I do that?
I managed to get a list of how many entries I have for each KEY, like this:
select count(*) from my_table group by KEY;
but how can I filter it to show only those who have the value 3?
select KEY
from my_table
group by KEY
having count(*) = 3
The having clause filters after grouping (where filters before).
select `key`
from my_table
group by `KEY`
having count(*) = 3;
select KEY
from my_table
group by KEY
having count(1) = 3
Try with Row Number concept
;
WITH Temp_tab AS
( SELECT '1' Key_,'az' Key_Value
UNION SELECT '1' ,'a5'
UNION SELECT '1' ,'a6'
UNION SELECT '2' ,'a1'
UNION SELECT '3' ,'a2'
UNION SELECT '4' ,'a3'
UNION SELECT '1' ,'a4'
UNION SELECT '3' ,'a21'
UNION SELECT '3' ,'a22'),
Tab2 AS
(SELECT *, ROW_NUMBER() over(partition BY key_ ORDER BY key_) count_ FROM Temp_Tab)
SELECT key_
FROM tab2 WHERE count_ = 3
code for your table
;with temp_table
(select *,ROW_NUMBER() over(partition by key_ order by key_) count_ from my_table)
select key_ from temp_table where count_ = 3
I am trying to create SQL Select that returns counts of a certain field based on a field.
So, here is what I am trying to do.
Select count(distinct id) as TotalCount, -- this will be the total of id
count(distinct id where type='A') as TotalA, -- this will be total when type='A'
count(distinct id where type='B') as TotalB -- This will be total when type = 'B'
from MyTable
Basically, TotalCount = TotalA + TotalB.
How can I achieve this in SQL Select Statement?
Thanks.
Select count(distinct id) as TotalCount, -- this will be the total of id
count(distinct case type when 'A' then id else NULL end) as TotalA,
count(distinct case type when 'B' then id else NULL end) as TotalB
from MyTable;
Of course TotalCount may or may not be TotalA + TotalB, depending on the actual data.
You can do it like that:
SELECT
count(distinct id) as TotalCount,
sum(CASE WHEN type = 'A' THEN 1 ELSE 0) as TotalA,
sum(CASE WHEN type = 'B' THEN 1 ELSE 0) as TotalB,
FROM
MyTable
Count per type:
SELECT
type,
count(DISTINCT id)
FROM
MyTable
GROUP BY
type
Why not simply UNION the separate queries.
Select 'all' as which, count(distinct id) as Total from mytable
union
select 'a' as which, count(distinct id) where type='A' as Total from mytable
union
select 'b' as which, count(distinct id) where type='B' as Total from mytable