Multiple matches on same row - mysql

Say for example I have one Order coupled with multiple items.
How do I list them on the same row (for example 3 items) ?
I already tried this
SELECT order.ID, item.name , item.qty , item2.name,item2.qty,item3.name,item3.qty
FROM order
JOIN item ON order.id = item.id
JOIN item as item2 ON order.id = item2.id
JOIN item as item3 ON order.id = item3.id
But how to avoid selecting the same item multiple times ?
Thanks in advance

In TSQL you can write a query as:
DECLARE #order TABLE (id int)
INSERT INTO #order VALUES (1)
DECLARE #item TABLE (id INT,NAME VARCHAR(10),qty INT)
INSERT INTO #item VALUES (1,'A',1),(1,'B',1),(1,'C',3)
SELECT
O.id AS OrderId,
STUFF
(
(
SELECT ', Name:' + NAME + ', Qty:' + CAST (qty AS VARCHAR(10))
FROM #item I
WHERE I.Id = O.Id
ORDER BY I.Id
FOR XML PATH(''), type
).value('.', 'varchar(max)'), 1, 1, ''
) AS Models
FROM
#order O

Related

how to add value to json type column in sub-query

I have to combine recordObj and recTime
I tried json_insert function to add recTime property in recordObj in select statement
It is not returning any records and just giving OK message
note : I can't change table structure.
mysql sp:
CREATE DEFINER=`root`#`localhost` PROCEDURE `records_get_upcomings`(in p_parent varchar(15))
BEGIN
WITH RECURSIVE cte (p_parent) AS (
SELECT child FROM connections WHERE parent = p_parent
UNION ALL
SELECT child FROM connections JOIN cte on connections.parent = cte.p_parent
)
select recordid, `current`, group_concat(past) as past from (
select * from
(
select cur.recordObj as `current`, past.recordObj as past, cur.recordid as recordid from
(select recordid, json_insert(recordObj, '$recTime', recTime) as recordObj, rec_status from records inner join cte on records.`from` = cte.p_parent) cur
cross join
(select recordid, json_insert(recordObj, '$recTime', recTime) as recordObj, rec_status from records inner join cte on records.`from` = cte.p_parent and records.`from` = cte.p_parent) past
where past.rec_status = 1 and cur.rec_status = 0 and past.recordid = cur.recordid
) as a
union
(
select recordObj as `current`, null as past, recordid from records inner join cte on records.`from` = cte.p_parent where rec_status = 0
)
) as t group by `current`;
END
records table :
from -> varchar
recordObj -> json
recordid -> varchar
recTime -> datetime
rec_status -> tinyint
u_rec_id -> int
any help is appreciated...

How to retrieve all members from a transitive relationship through one SQL query [duplicate]

I have a table with following structure
Table name: matches
That basically stores which product is matching which product. I need to process this table
And store in a groups table like below.
Table Name: groups
group_ID stores the MIN Product_ID of the Product_IDS that form a group. To give an example let's say
If A is matching B and B is Matching C then three rows should go to group table in format (A, A), (A, B), (A, C)
I have tried looking into co-related subqueries and CTE, but not getting this to implement.
I need to do this all in SQL.
Thanks for the help .
Try this:
;WITH CTE
AS
(
SELECT DISTINCT
M1.Product_ID Group_ID,
M1.Product_ID
FROM matches M1
LEFT JOIN matches M2
ON M1.Product_Id = M2.matching_Product_Id
WHERE M2.matching_Product_Id IS NULL
UNION ALL
SELECT
C.Group_ID,
M.matching_Product_Id
FROM CTE C
JOIN matches M
ON C.Product_ID = M.Product_ID
)
SELECT * FROM CTE ORDER BY Group_ID
You can use OPTION(MAXRECURSION n) to control recursion depth.
SQL FIDDLE DEMO
Something like this (not tested)
with match_groups as (
select product_id,
matching_product_id,
product_id as group_id
from matches
where product_id not in (select matching_product_id from matches)
union all
select m.product_id, m.matching_product_id, p.group_id
from matches m
join match_groups p on m.product_id = p.matching_product_id
)
select group_id, product_id
from match_groups
order by group_id;
Sample of the Recursive Level:
DECLARE #VALUE_CODE AS VARCHAR(5);
--SET #VALUE_CODE = 'A' -- Specify a level
WITH ViewValue AS
(
SELECT ValueCode
, ValueDesc
, PrecedingValueCode
FROM ValuesTable
WHERE PrecedingValueCode IS NULL
UNION ALL
SELECT A.ValueCode
, A.ValueDesc
, A.PrecedingValueCode
FROM ValuesTable A
INNER JOIN ViewValue V ON
V.ValueCode = A.PrecedingValueCode
)
SELECT ValueCode, ValueDesc, PrecedingValueCode
FROM ViewValue
--WHERE PrecedingValueCode = #VALUE_CODE -- Specific level
--WHERE PrecedingValueCode IS NULL -- Root

Insert multiple arrays' values into tables using index

Cont. with this post, a function is created to parse json input then insert values into three tables, with previous inserted ids as parameter for last
insert.
If i want to insert two arrays into the same table, i can just do
insert into t2 (car, car_type)
select json_array_elements_text(d::json -> 'car'),json_array_elements_text(d::json -> 'car_type')::int4 returning id;
)
how to make it work with index as below?
function:
create or replace function test_func(d json)
returns void as $$
begin
with j as (select d)
, a as (
select car,brand,type, t1.id oid
from j
join json_array_elements_text(j.d->'cars') with ordinality t1(car,id) on true
join json_array_elements_text(j.d->'brands') with ordinality t2(brand,id)
on t1.id = t2.id
join json_array_elements_text(j.d->'car_type') with ordinality t2(type,id)
on t1.id = t2.id // this line apparently doesnt work, t2 has been joined twice
)
, n as (
insert into t1 (name) values (d::json -> 'name') returning id
), c as (
insert into t2 (cars,car_type) select car,type from a order by oid returning id // needs to insert two columns here from two arrays
)
, ag as (
select array_agg(c.id) cid from c
)
insert into t3 (id, name_id, cars_id, brand)
select 1, n.id,cid[oid], brand
from a
join n on true
join ag on true
;
end;
$$ language plpgsql;
Tables:
CREATE TABLE t1 ( "id" SERIAL PRIMARY KEY, "name" text NOT NULL );
CREATE TABLE t2 ( "id" SERIAL PRIMARY KEY, "cars" text NOT NULL, "car_type" int );
CREATE TABLE t3 ( "id" int, "name_id" int REFERENCES t1(id), "cars_id" int REFERENCES t2(id), "brand" text );
Test:
select test_func('{"name":"john", "cars":["bmw X5 xdrive","volvo v90 rdesign"], "brands":["bmw","volvo"],"car_type":[1,1]}');
you used t2 for aliasing two different sets - try:
create or replace function test_func(d json)
returns void as $$
begin
with j as (select d)
, a as (
select car,brand,car_type, t1.id oid
from j
join json_array_elements_text(j.d->'cars') with ordinality t1(car,id) on true
join json_array_elements_text(j.d->'brands') with ordinality t2(brand,id)
on t1.id = t2.id
join json_array_elements_text(j.d->'car_type') with ordinality car_t(car_type,id)
on t1.id = car_t.id
)
, n as (
insert into t1 (name) values (d::json -> 'name') returning id
), c as (
insert into t2 (cars,car_type) select car,car_type::int from a order by oid returning id -- needs to insert two columns here from two arrays
)
, ag as (
select array_agg(c.id) cid from c
)
insert into t3 (id, name_id, cars_id, brand)
select 1, n.id,cid[oid], brand
from a
join n on true
join ag on true
;
end;
$$ language plpgsql;
result:
t=# select * from t2;
id | cars | car_type
----+-------------------+----------
1 | bmw X5 xdrive | 1
2 | volvo v90 rdesign | 1
(2 rows)

optimise query with calculate field from several tables

I have four tables
store[store_id(pk),name]
itemsA(item_id(pk),store_id,name)
itemB(item_id(pk),store_id,name)
itemC(item_id(pk),store_id,name)
I want a query to retrieve a store and the number of items that he have. something like :
select s.store_id ,s.name,count() as numberOfItems from store limit 100
what is the optimal query to achieve that with the following restraints :
cannot create a function in the db
cannot create view
I can only run queries on the db
Thanks
I would recommend doing this with correlated subqueries:
select s.store_id, s.name,
((select count(*) from itemsA a where a.store_id = s.store_id) +
(select count(*) from itemsB b where b.store_id = s.store_id) +
(select count(*) from itemsC c where c.store_id = s.store_id)
) as numberOfItems
from store s
limit 100;
You then want an index in each of the item tables: itemsA(stored_id), itemsB(store_id), and itemsC(store_id).
The reason this is optimized is because it only has to calculate the values for the arbitrary 100 stores chosen by the limit. And, the calculation can be done directly from the index. Other approaches will require doing the calculation for all the stores.
Note: usually when using limit you want an order by clause.
Stores with no items will not show up with this query. If this is a requirement it will have to be tweaked somewhat.
SELECT s.store_id, COUNT(*)
FROM Store s
JOIN ItemA a ON a.store_id = s.store_id
JOIN ItemB b ON b.store_id = s.store_id
JOIN ItemC c ON c.store_id = s.store_id
GROUP BY s.store_id
A simple modification to also include stores with 0 items:
SELECT s.store_id, COUNT(a.store_id) + COUNT(b.store_id) + COUNT(c.store_id)
FROM Store s
LEFT JOIN ItemA a ON a.store_id = s.store_id
LEFT JOIN ItemB b ON b.store_id = s.store_id
LEFT JOIN ItemC c ON c.store_id = s.store_id
GROUP BY s.store_id
If i understood you correctly
DECLARE #store TABLE (store_id INT, name NVARCHAR(100))
DECLARE #itemsA TABLE (item_id INT,store_id INT, name NVARCHAR(100))
DECLARE #itemsB TABLE (item_id INT,store_id INT, name NVARCHAR(100))
DECLARE #itemsC TABLE (item_id INT,store_id INT, name NVARCHAR(100))
INSERT INTO #store VALUES (1,'Store1')
INSERT INTO #store VALUES (2,'Store2')
INSERT INTO #itemsA VALUES (1,1,'itemsA_item1')
INSERT INTO #itemsA VALUES (2,1,'itemsA_item2')
INSERT INTO #itemsA VALUES (3,1,'itemsA_item3')
INSERT INTO #itemsB VALUES (1,2,'itemsB_item1')
INSERT INTO #itemsB VALUES (2,2,'itemsB_item2')
INSERT INTO #itemsB VALUES (3,2,'itemsB_item3')
INSERT INTO #itemsB VALUES (4,1,'itemsB_item4')
INSERT INTO #itemsC VALUES (1,3,'itemsC_item1')
INSERT INTO #itemsC VALUES (2,3,'itemsC_item2')
INSERT INTO #itemsC VALUES (3,2,'itemsC_item3')
SELECT TOP 100 store_id, SUM(HasItems) AS TotalItems FROM
(
SELECT store_id, COUNT(name) AS HasItems FROM #itemsA GROUP BY store_id
UNION
SELECT store_id, COUNT(name) AS HasItems FROM #itemsB GROUP BY store_id
UNION
SELECT store_id, COUNT(name) AS HasItems FROM #itemsC GROUP BY store_id
) AS StoreItems
GROUP BY store_id

sum of elements in mysql

We have a mysql table which has following schema
item varchar(20)
count int
We have a chart which classifies the items into categories (item1 and item2 belongs to cat1 and item3, item4 belongs to cat4, but that is not in a table and we cannot create a table.
I want the count of items present in the cat1 and cat2. Can this be done without joining with any table and with inner query ?
SELECT 'Cat1', sum(table1.count) FROM Table1 WHERE item IN ('Item1','Item2') UNION SELECT 'Cat2', sum(table1.count) FROM Table1 WHERE item IN ('Item3','Item4');
You can do this:
SELECT
c.categoryname,
SUM(IFNULL(i.`count`,0))
FROM
(
SELECT 'item1' itemname, 'cat1' CategoryName
UNION ALL
SELECT 'item2' , 'cat1'
UNION ALL
SELECT 'item3' , 'cat2'
UNION ALL
...
) c
LEFT JOIN items i ON c.itemname = i.item
GROUP BY c.categoryname
SQL Fiddle Demo