Convert row to unknown column - ms-access

I have table ITEM of
ID | NAME
---------
1 | A
2 | B
3 | C
4 | D
5 | E
6 | F
If I Enter : 2 I want the table to be like that
ID | NAME_1 | NAME_2
--------------------
1 | A | B
2 | C | D
3 | E | F
If I Enter : 3 I want the table to be like that
ID | NAME_1 | NAME_2 | NAME_3
-----------------------------
1 | A | B | C
2 | D | E |
What is the query to achieve that? (My db is Ms-Access)

First, create a query, QParts, to build the field names:
PARAMETERS
P Short;
SELECT
([ID] - 1) \ [P] + 1 AS NewID,
"NAME_" & CStr(([ID] - 1) Mod [P] + 1) AS FieldName,
Itemx.NAME AS [Value]
FROM
Item;
Then create a crosstab query:
PARAMETERS
P Short;
TRANSFORM
First(QParts.Value) AS NewValue
SELECT
QParts.NewID
FROM
QParts
GROUP BY
QParts.NewID
PIVOT
QParts.FieldName;
Output, P = 2:
Output, P = 3:

Related

SQL/MySQL - Select and return array column on one-to-many table join [duplicate]

We have 3 tables :
donations
purposes
expenses
Donations :
+--------+------+
| do_id | name |
+--------+------+
| 1 | A |
| 2 | B |
| 3 | A |
| 4 | D |
| 5 | B |
| 6 | B |
| 7 | A |
| 8 | B |
+--------+----- +
purposes:
+-------+-------+--------+
| pu_id | do_id | purpose|
+-------+-------+--------+
| 1 | 2 | abc |
| 2 | 2 | def |
| 3 | 2 | gih |
| 4 | 3 | jkl |
+-------+-------+--------+
expense :
+-------+-------+---------+
| ex_id | do_id | expense |
+-------+-------+---------+
| 1 | 2 | abc |
| 2 | 2 | def |
| 3 | 2 | gih |
| 4 | 3 | jkl |
+-------+-------+---------+
Now i want to make query to get all donations for donor B and join purposes table to get all purposes related to every donation_id then join expenses table to get all expenses related to donation_id and put all of that in every loop independently something like that
Row number 0
donation_id = 1
array(purposes)
array(expenses)
Row number 1
donation_id = 2
array(purposes)
array(expenses)
Row number 2
donation_id = 3
array(purposes)
array(expenses)
Row number 3
donation_id = 4
array(purposes)
array(expenses)
This is my try :
SELECT *, (
SELECT *
FROM `donation_purposes`
WHERE `donation_purposes`.`dopu_donation_id` = 4
) AS `purposes`
FROM `donations`
WHERE `donation_id` = '4'
thanks in advance
You should be able to solive this with an aggregate query using MySQL aggregate function JSON_ARRAYAGG(), like :
SELECT
d.do_id,
JSON_ARRAYAGG(p.purpose) purposes,
JSON_ARRAYAGG(e.expense) expenses
FROM donations d
INNER JOIN purposes p ON p.do_id = d.do_id
INNER JOIN expense e ON e.do_id = d.do_id
GROUP BY d.do_id
I you want to avoid duplicate values in the array, and as JSON_ARRAYAGG() (sadly) does not support the DISTINCT option, you can move aggregation to subqueries, like :
SELECT
d.do_id,
p.agg purpose,
e.agg expenses
FROM donations d
INNER JOIN (
SELECT do_id, JSON_ARRAYAGG(purpose) agg FROM purposes GROUP BY do_id
) p ON p.do_id = d.do_id
INNER JOIN (
SELECT do_id, JSON_ARRAYAGG(expense) agg FROM expense GROUP BY do_id
) e ON e.do_id = d.do_id
This demo on DB Fiddle returns :
| do_id | purpose | expenses |
| ----- | --------------------- | --------------------- |
| 2 | ["abc", "def", "gih"] | ["abc", "def", "gih"] |
| 3 | ["jkl"] | ["jkl"] |
1st Select Query Purposes
SELECT purposes.* FROM purposes
LEFT JOIN donations
ON purposes.do_id = donations.do_id
WHERE donations.do_id = '2' //This depends on the id of the donation
ORDER BY purposes.do_id ASC
2nd Select Query Expenses
SELECT expense.* FROM expense
LEFT JOIN donations
ON expense.do_id = donations.do_id
WHERE donations.do_id = '2' //This depends on the id of the donation
ORDER BY expense.ex_id ASC
All queries generated are from the table structure you've provided, but your question is quite vague!!

how to remove rows that are related to same values

how do I turn this:
| ID | LETTER
----------------
| 1 | A
| 2 | B
| 3 | B
| 4 | C
| 5 | D
| 6 | D
| 7 | F
| 8 | A
On this:
| ID | LETTER
----------------
| 4 | C
| 7 | F
There are multiple ways to solve this problem, one possible way is -
SELECT
*
FROM
t_system_log;
SELECT
t_table.*
FROM
t_table,
(
SELECT
letter
FROM
t_table
GROUP BY
letter
HAVING
count(letter) = 1) AS t_unique
WHERE
t_table.letter = t_unique.letter
;
My Fiddle
I'm using SQL 5.6,
If the table name is t_name,
Then simplest query to remove rows that are related to same values:
*
SELECT * FROM t_name
Group by LETTER having count(LETTER)=1;

Update when null insert when does not exist

I have a table with multiple records have the same ID but different values. I want copy records from other table to this table. I want to update if record is null to the minimum position, or insert into the next position if the value does not exist.
Here is my Target table:
ID | Position | Value
1 | 1 | A
2 | 1 | B
2 | 2 | null
2 | 3 | null
2 | 4 | C
3 | 1 | A
4 | 1 | D
4 | 2 | B
Source table:
ID | Value
1 | C
2 | N
3 | B
4 | D
5 | A
6 | null
7 | B
Wanted result table:
ID | Position | Value
1 | 1 | A
1 | 2 | C
2 | 1 | B
2 | 2 | N
2 | 3 | null
2 | 4 | C
3 | 1 | A
3 | 2 | B
4 | 1 | D
4 | 2 | B
5 | 1 | A
7 | 1 | B
My query is:
MERGE Target AS T
USING (SELECT S.ID, MAX(E.POS) AS PosMax, MIN(E.POS) as PosMin, S.Value
FROM Source S
LEFT OUTER JOIN Target E ON S.ID = E.ID
WHERE S.Value IS NOT NULL AND E.Value IS NULL
GROUP BY S.ID, S.Value) AS SC
ON T.ID = SC.ID
WHEN MATCHED AND SC.Value IS NOT NULL AND EG.Value IS NULL AND T.POS = SC.PosMin
THEN
UPDATE SET
EG.Value = SC.Value
WHEN NOT MATCHED AND SC.Value IS NOT NULL
THEN
INSERT (ID, Position, Value)
VALUES (SC.D, ISNULL(SC.PosMax, 0) + 1, SC.Value);
This only updates the null value with the minimum position and insert the value if there is not exist ID. If the ID existed. It will not insert because the Match T.ID = SC.ID.
Example of ID 3, It does not inser value B in position 2.
Does anyone have different approach or strategy? Or I have to write a second query to insert if the ID is the same and value not.
Thanks,
Jay
I think your ON needs the position as well.
ON T.ID = SC.ID and T.pos=SC.minpos.
And the subquery to build SC should be an inner join. You don't want records if you don't have matching values in target.

Get all from left table event if there is nothing in join table

Here is the table structure for Clinic has many Categories:
Clinic Category
id company_id | clinic_id | type
--- -----------------------------
1 -> 1 | 1 | pre
2 | 1 | pre
2 -> 1 | 2 | ext
2 | 2 | ext
3 -> 1 | 3 | pre
4 -> 2 | 4 | ext
5 -> 2 | 5 | pre
Here, I want to get all clinics in the output ordered by first pre then ext. But, sometimes I have check a condition against company_id (eg: 1, in the following try) and I don't want the clinics to be filtered out.
My Try
Clinic.joins("LEFT JOIN categories c ON c.clinic_id = clinics.id").
order("
CASE c.type
WHEN 'pre' THEN 0
WHEN 'ext' THEN 1
ELSE 2
END
").
where("c.company_id = 1 OR c.company_id IS NULL")
The problem is, as can be seen in the table structure, if I don't have a clinic that matches a category with company id 1, it gets filtered out, but, still I want that clinic to be part of output with type other.
Expected Output For Company ID = 1
Clinic Category
id company_id | clinic_id | type
--- -----------------------------
1 -> 1 | 1 | pre
3 -> 1 | 3 | pre
2 -> 1 | 2 | ext
4 -> NULL | NULL | NULL(or other)
5 -> NULL | NULL | NULL(or other)
Expected Output For Company ID = 2
Clinic Category
id company_id | clinic_id | type
--- -----------------------------
1 -> 2 | 1 | pre
5 -> 2 | 5 | pre
2 -> 2 | 2 | ext
4 -> 2 | 4 | ext
3 -> NULL | NULL | NULL (or other)
In the left join itself, filter the company_id like below
LEFT JOIN categories c ON c.clinic_id = clinics.id AND c.company_id = 1
Hope this would help you out.

MySql/Oracle Remove gaps of numeric column

First of all, I need a solution for Oracle and MySQL.
I Have a folder table :
id | name | parent_id | position
_________________________________
1 | root | null | 1
2 | a | 1 | 1
3 | b | 1 | 2
4 | b1 | 3 | 1
5 | b2 | 3 | 2
6 | c | 1 | 3
7 | d | 1 | 4
8 | e | 1 | 5
given the tree :
root
|_ a
|_ b
| |_b1
| |_b2
|_c
|_d
|_e
The column position has a NOT NULL and UNIQUE constraint.
Problem :
Sometimes i have to delete some folders in a single query (ex : delete folder 'a', 'b1', 'd'). When doing this i have gaps in folders position :
id | name | parent_id | position
_________________________________
1 | root | null | 1
3 | b | 1 | 2
5 | b2 | 3 | 2
6 | c | 1 | 3
8 | e | 1 | 5
So I need to update the table in single request for updating the position column and in a specific order (to prevent the UNIQUE constraint) to obtain the result :
id | name | parent_id | position
_________________________________
1 | root | null | 1
3 | b | 1 | 2
5 | b2 | 3 | 1
6 | c | 1 | 2
8 | e | 1 | 3
Any Idea ?
Thanks
Try this
MERGE
INTO YourTable t1
USING (
SELECT pk_id, gap_ID, row_num() over (order by gap_id) as newGap
FROM YourTable t2
) as sub
ON (t1.pk_id = t2.pk_id)
WHEN MATCHED THEN
UPDATE
SET gap_ID = newGap;
I solved the problem :
Oracle
UPDATE folders t
SET position = ( select count(*)
FROM folders f1 INNER JOIN folders f2 on ( f1.parent_id = f2.parent_id and f1.position >= f2.position )
WHERE f1.id = t.id AND t.parent_id = f1.parent_id
GROUP BY f1.id, f1.position );
MySQL
UPDATE folders f
INNER JOIN ( select f1.id, f1.parent_id, count(*) as newPos
FROM folders f1 INNER JOIN folders f2 on ( f1.parent_id = f2.parent_id and f1.position >= f2.position)
GROUP BY f1.parent_id, f1.position) t on ( t.id = f.id and t.parent_id = f.parent_id)
SET f.position = t.newPos