How can I order by two same attributes from differents tables? - sql

I've got this DB. For starters, I didn't created this DB and I can't change the structure, so I have to deal with it.
+------+ +--------+ +--------+
| FORM | | FORM_A | | FORM_B |
+------+ +--------+ +--------+
| id | | form_id| | form_id|
| name | | name |
I'm not an Oracle user, I need to get all the FORM where I will get FORM_A datas as well as FORM_B, but I need to order it by name from both tables. "name" is the same kind of datas from FORM_A and FORM_B, too bad it's not in FORM.
Exemple :
FORM_A = [a, b, d, f]
FORM_B = [e, c, g]
FORM datas must be ordered as FORM_A(a), FORM_A(b), FORM_B(c), FORM_A(d), FORM_B(e)...
At first I think I'll have to order it manually with some loops, but I wonder if there is a way to order from multiples tables together, and not one after the other ?

you can
select *
from ( select id, null as name from form union all
select id, name from formA union all
select id, name from formB
) temp
order by temp.name

I am assuming the following table contents:
FORM FORM_A FORM_B
+----+--------+ +------+---------+ +------+---------+
| ID | NAME | | NAME | FORM_ID | | NAME | FORM_ID |
+----+--------+ |+-----+---------+ |+-----+---------+
| 1 | First | | a | 1 | | e | 3 |
| 2 | Second | | b | 2 | | c | 4 |
| 3 | Third | | d | 2 | | g | 5 |
| 4 | Fourth | | f | 3 | +------+---------+
| 5 | Fifth | +------+---------+
+----+--------+
You can use UNION to select from two tables, provided that the two tables have the same column structure:
SELECT FORM_A.form_id, FORM_A.name
FROM FORM_A
UNION ALL
SELECT FORM_B.form_id, FORM_B.name
FROM FORM_B
ORDER BY name;
FORM_ID NAME
---------- -----
1 a
2 b
4 c
2 d
3 e
3 f
5 g
By joining the FORM_ID with the FORM table, you then get the corresponding rows from FORM:
SELECT ab.Name AS AB, f.Name AS DATA
FROM (SELECT FORM_A.form_id, FORM_A.name
FROM FORM_A
UNION ALL
SELECT FORM_B.form_id , FORM_B.name
FROM FORM_B
ORDER BY name) ab
JOIN FORM f ON f.id=ab.FORM_ID;
AB DATA
----- ----------
a First
b Second
c Fourth
d Second
e Third
f Third
g Fifth

Related

SQL select all rows that are not equal to an id, and replace the id column with the value - without cross join

Say I have a table like this:
+----+-------+
| id | value |
+----+-------+
| 1 | a |
| 1 | b |
| 2 | c |
| 2 | d |
| 3 | e |
| 3 | f |
+----+-------+
And I want to select all rows with id that are not a, and change their id to a; select all rows with id that are not b, and change the id to b; and select all rows with id that are not c, and change their id to c.
Here is the output I want:
+----+-------+
| id | value |
+----+-------+
| 1 | c |
| 1 | d |
| 1 | e |
| 1 | f |
| 2 | a |
| 2 | b |
| 2 | e |
| 2 | f |
| 3 | a |
| 3 | b |
| 3 | c |
| 3 | d |
+----+-------+
The only solution I can think of is through cross join and distinct:
select distinct a.id, b.value
from table a
cross join table b
where a.id != b.id
Is there any other way to avoid such expensive operation?
I think the typical way to write this is to generate all pairs of id and value and then remove the ones that exist:
select i.id, v.value
from (select distinct id from t) i cross join
(select distinct value from t) v left join
t
on t.id = i.id and t.value = i.value
where t.id is null;
First, I don't think this is what your query does. But this is what you seem to be describing.
From a performance perspective, you might have other sources for i and v that don't require subqueries. If so, use those for performance.
Finally, I don't think you can do much to improve the performance of this, apart from using explicit tables -- and perhaps having appropriate indexes on all the tables.

Selecting the two most common attribute pairings from a Entity-Attribute Table?

I have a simple Entity-Attribute table in my database describing simply if an Entity has some Attribute by the existance of a row consisting of (Entity, Attribute).
I want to find out, of all the Entities with two and only two Attributes, what are the most common Attribute pairs
For example, if my table looked like:
+--------+-----------+
| Entity | Attribute |
+--------+-----------+
| Bob | A |
| Sally | B |
| Terry | C |
| Bob | B |
| Sally | A |
| Terry | D |
| Larry | C |
+--------+-----------+
I would want it to return
+-------------+-------------+-------+
| Attribute-1 | Attribute-2 | Count |
+-------------+-------------+-------+
| A | B | 2 |
| C | D | 1 |
+-------------+-------------+-------+
I currently have a short query that looks like:
WITH TwoAtts (
SELECT entity
FROM table
GROUP BY entity
HAVING COUNT(att) = 2
)
SELECT t1.att, t2.att, COUNT(entity)
FROM table t1
JOIN table t2
ON t1.entity = t2.entity
WHERE t1.entity IN (SELECT * FROM TwoAtts)
AND t1.att != t2.att
GROUP BY t1.att, t2.att
ORDER BY COUNT(entity) DESC
but is only capable of producing "duplicate" results like
+-------------+-------------+-------+
| Attribute-1 | Attribute-2 | Count |
+-------------+-------------+-------+
| A | B | 2 |
| B | A | 2 |
| D | C | 1 |
| C | D | 1 |
+-------------+-------------+-------+
In a sense I would like to be able to run a unordered DISTINCT / set operator over the two attribute columns, but I am not sure how to acheive this functionality in SQL?
Hmmm, I think you want two levels of aggregation, with some filtering:
select attribute_1, attribute_2, count(*)
from (select min(ea.attribute) as attribute_1, max(ea.attribute) as attribute_2
from entity_attribute ea
group by entity
having count(*) = 2
) aa
group by attribute_1, attribute_2;
Here is a db<>fiddle

Identifying heirarchical groupings from a Parent-Child associaiton list in SQL

I am trying to identify groupings of accounts from a Parent-Child association table in SQL. Rather than a big hierarchy tree, I am dealing with many small trees and I need to identify each Tree as a unique Group in order to label related accounts.
I have two tables, a table of all Unique ID's:
+------+-------+
| ID | Group |
+------+-------+
| A | NULL |
| B | NULL |
| C | NULL |
| etc. | NULL |
+------+-------+
And a Table showing Parent - Child association between them:
+--------+-------+
| Parent | Child |
+--------+-------+
| A | D |
| A | E |
| B | F |
| B | G |
| B | C |
| C | H |
+--------+-------+
I Need to Fill the Group field of my first table so that I can identify all accounts which have a direct or indirect relationship eg:
+----+-------+
| ID | Group |
+----+-------+
| A | 1 |
| B | 2 |
| C | 2 |
| D | 1 |
| E | 1 |
| F | 2 |
| G | 2 |
| H | 2 |
+----+-------+
Where I'm struggling is that a Parent could be a Child to another Parent eg:
Parent B -> Parent -> C -> Child H
These form a Group but there is no direct link between B and H and I am struggling to find a reliable way to identify all associated ID's
This type of logic requires a recursive CTE. The idea is to start at the parents and work your way down the hierarchy:
with cte as (
select row_number() over (order by node) as grp,
n.node as ultimate_parent, n.node as node, 1 as lev
from nodes n
where not exists (select 1 from pc where pc.child = n.node)
union all
select cte.grp, cte.ultimate_parent, pc.child, lev + 1
from cte join
pc
on cte.node = pc.parent
)
update nodes
set grp = cte.grp
from cte
where cte.node = nodes.node;
Here is a db<>fiddle.

SSRS Multiple Lines of data

My SQL Server 2008 report returns me multiple lines in a table. A simple select statement returns two columns, one is the record number the other is a sector. The sector column can contain any one of 6 different values.
EDIT: NULL values are allowed in the sector column.
I want this data to be in one line in my table.
Lets say record number 1 has Sector A, Sector C and Sector E
and Record 2 has Sector B and Sector C
And Record 3 has none.
I am after three lines of data. I also need it displayed two ways. One so that all sectors appear in the same cell separated by commas. The other is a separate Cell for each category
Record number | Sector
1 | A, C, E
2 | B, C
3 |
Or
Record Number | Sector A | Sector B | Sector C | Sector D | Sector E
1 | A | | C | | E
2 | | B | C | |
3 | | | | |
At the moment my report gives me 6 rows.
Record Number | Sector
1 | A
1 | C
1 | E
2 | B
2 | C
3 |
Is there a way of working around this problem?
I am using the query designer rather than writing the SQL statements.
In order to get the first result that you want with the comma-separated list of sector values, you will want to use FOR XML PATH and STUFF. The code will be:
select t1.recordnumber,
STUFF((SELECT ', ' + t2.sector
from yourtable t2
where t1.recordnumber = t2.recordnumber
FOR XML PATH (''))
, 1, 1, '') AS Sector
from yourtable t1
group by t1.recordnumber
See SQL Fiddle with Demo. The result is:
| RECORDNUMBER | SECTOR |
---------------------------
| 1 | A, C, E |
| 2 | B, C |
| 3 | (null) |
Then to get the result of the recordNumber in a single row, you can use the PIVOT function:
select *
from
(
select recordNumber, sector
from yourtable
) src
pivot
(
max(sector)
for sector in (A, B, C, D, E)
) piv;
See SQL Fiddle with Demo. The result of this query is:
| RECORDNUMBER | A | B | C | D | E |
-------------------------------------------------------------
| 1 | A | (null) | C | (null) | E |
| 2 | (null) | B | C | (null) | (null) |
| 3 | (null) | (null) | (null) | (null) | (null) |

How to count rows that have the same values in two columns (SQL)?

I am sure there must be a relatively straightforward way to do this, but it is escaping me at the moment. Suppose I have a SQL table like this:
+-----+-----+-----+-----+-----+
| A | B | C | D | E |
+=====+=====+=====+=====+=====+
| 1 | 2 | 3 | foo | bar | << 1,2
+-----+-----+-----+-----+-----+
| 1 | 3 | 3 | biz | bar | << 1,3
+-----+-----+-----+-----+-----+
| 1 | 2 | 4 | x | y | << 1,2
+-----+-----+-----+-----+-----+
| 1 | 2 | 5 | foo | bar | << 1,2
+-----+-----+-----+-----+-----+
| 4 | 2 | 3 | foo | bar | << 4,2
+-----+-----+-----+-----+-----+
| 1 | 3 | 3 | foo | bar | << 1,3
+-----+-----+-----+-----+-----+
Now, I want to know how many times each combination of values for columns A and B appear, regardless of the other columns. So, in this example, I want an output something like this:
+-----+-----+-----+
| A | B |count|
+=====+=====+=====+
| 1 | 2 | 3 |
+-----+-----+-----+
| 1 | 3 | 2 |
+-----+-----+-----+
| 4 | 2 | 1 |
+-----+-----+-----+
What would be the SQL to determine that? I feel like this must not be a very uncommon thing to want to do.
Thanks!
SELECT A,B,COUNT(*)
FROM the-table
GROUP BY A,B
TRY:
SELECT
A, B , COUNT(*)
FROM YourTable
GROUP BY A, B
This should do it:
SELECT A, B, COUNT(*)
FROM TableName
GROUP BY A, B;
SELECT A,B,COUNT(1) As COUNT_OF
FROM YourTable
GROUP BY A,B
SELECT A,B,COUNT(*)
FROM table
GROUP BY A,B
SELECT A, B, COUNT(*)
FROM MyTable
GROUP BY A, B
This could be the answer:
SELECT a, b, COUNT(*)
FROM <your table name here>
GROUP BY a,b
ORDER BY 3 DESC;