Query SQL Select Column Matching From Another Table - sql

edit : Sorry gurus, I have to rephrase my question since I forgot there are 3 tables in one query.
I have three tables with tbl_goods ,tbl_units and tbl_sat which looks like this :
tbl_goods, consists of sold goods
+--------+-------+-------+-------+
| goods |code |qty |unit |
+--------+-------+-------+-------+
| cigar | G001 | 1 | pack |
| cigar | G001 | 2 | pcs |
| bread | G002 | 2 | pcs |
| soap | G003 | 1 | pcs |
+--------+-------+-------+-------+
and tbl_units as below :
+--------+-------------+-------+
| code |ucode |qty |
+--------+-------------+-------+
| KG001 | U001 | 10 |
+--------+-------------+-------+
I add letter 'K' in front of code in tbl_units to differ and make sure not collide with code in tbl_goods.
and tbl_sat as below :
+--------+-------------+
| ucode | unit |
+--------+-------------+
| U001 | pack |
+--------+-------------+
| U002 | box |
+--------+-------------+
| U003 | crate | etc
so only cigar will have conversion because table units have the code
what the result I need to show as below :
+--------+-------+-------+-------+--------+
| goods |code |qty |unit | total |
+--------+-------+-------+-------+--------+
| cigar | G001 | 1 | pack | 10 |
| cigar | G001 | 2 | pcs | 2 |
| bread | G002 | 2 | pcs | 2 |
| soap | G003 | 1 | pcs | 1 |
+--------+-------+-------+-------+--------+
so if the code in goods doesn't have match in tbl_units then it will show just as qty in tbl_goods, but if they match then it will convert multiply from tbl_units
Thank you very much..really appreciated
regards
EDIT (might worked ?) :
I try to modify from #danielpr query, and this is the result
think it worked, please help to check it out
SELECT j.code,j.qty ,j.unit, IIF(j.unit=t.unit,j.qty*u.qty,j.fqty) FROM tbl_goods j
LEFT JOIN tbl_units u on u.code ='K' || j.code
LEFT JOIN tbl_sat t ON t.ucode =u.ucode [WHERE j.code='G001']
GROUP BY j.code,j.qty
[WHERE ..] optional if omitted will list all items, but if I just want to check the cigar..just put WHERE CLAUSE

If I understand correct, you are looking for a combination of LEFT JOIN and CASE WHEN or COALESCE.
Here the CASE WHEN option:
SELECT g.goods, g.code, g.qty, g.unit,
CASE WHEN u.conversion IS NULL
THEN g.qty
ELSE g.qty * u.qty
END AS total
FROM
tbl_goods g
LEFT JOIN tbl_units u
ON g.code = u.code
AND g.unit = u.conversion;
As said, COALESCE could also do and is a bit shorter:
SELECT g.goods, g.code, g.qty, g.unit,
g.qty * COALESCE(u.qty,1) AS total
FROM
tbl_goods g
LEFT JOIN tbl_units u
ON g.code = u.code
AND g.unit = u.conversion;
But I think this option has a worse readability compared to CASE WHEN.
Therefore, I would prefer CASE WHEN here.
Try out: db<>fiddle
EDIT because the authour changed the question:
According to the new description, a further table is involved and the table structure is other than described before. So, the COALESCE option is not possible at all in this case.
We require the CASE WHEN way here:
SELECT g.goods, g.code, g.qty, g.unit,
CASE WHEN u.qty IS NULL OR u.ucode IS NULL OR t.unit IS NULL
THEN g.qty
ELSE g.qty * u.qty
END AS total
FROM
tbl_goods g
LEFT JOIN tbl_units u ON u.code = CONCAT('K', g.code)
LEFT JOIN tbl_sat t ON u.ucode = t.ucode AND g.unit = t.unit;
New sample fiddle for this new situation: db<>fiddle

SELECT
tbl_goods.goods
, tbl_goods.code
, tbl_goods.qty
, tbl_goods.unit
, IF(tbl_goods.unit=tbl_units.conversion,tbl_goods.qty*tbl_units.qty,tbl_goods.qty) total
FROM tbl_goods
LEFT JOIN tbl_units ON tbl_goods.code=tbl_units.code
on total column, we can match whether the unit in tbl_goods is same with tbl_units, which is pack.
If it is the same, then we multiply the pack qty in tbl_units with the pack in tbl_goods, else, just return the qty of tbl_goods.

Related

SQL code to find if a series of lists do NOT contain a particular value

I have two tables
Jobs
+-----+------+
| Job | Name |
+-----+------+
| 1 | Foo |
| 2 | Bar |
| 3 | Baz |
| 4 | Qwe |
+-----+------+
Job_Operations
+-----+--------------+
| Job | Work_Center |
+-----+--------------+
| 1 | SomeCenter |
| 1 | Full Kit |
| 2 | SomeCenter |
| 3 | SomeCenter |
| 3 | Full Kit |
+-----+--------------+
The tables are linked on the Job column. How can I find the entries in Jobs without a corresponding 'Full Kit' entry in Job_Operations?
Desired Results
+-----+------+
| Job | Name |
+-----+------+
| 2 | Bar |
| 4 | Qwe |
+-----+------+
This seems like a straight forward NOT EXISTS query
SELECT J.*
FROM Jobs J
WHERE NOT EXISTS(SELECT *
FROM Job_Operations JO
WHERE JO.Job = J.Job
AND JO.Work_Center = 'Full Kit')
Select * from
(
select Jobs.* , job_Operations.Work_Center as wc
from Jobs
left join Job_Operations on Jobs.Job=Job_Operations.Job and Job_Operations.Work_Center='Full Kit'
) as sub1 where wc is null
In the subselect left join tells the SQL server to give me a row for every row in the Jobs table, even if it does not find a corresponding value in the job_Operations. From job_Operations only rows that contain your 'Full Kit' are regarded for the join. If the join fails, SQLsefer just returns a null for the fields in job_Operations. The outer select just fetches those rows.
Another way is to use Exists, see how that works in the other answer. But if you want to learn SQL try to get an understanding of how left, right inner and outer/full join work.
Simple solution in code below.
Also keep in mind that "working" doesn't meant "high performance".
Check SQL-plan on your specific DB.
select j.*
from job j
where j.job not in (select jo.job
from Job_Operations jo
where jo.Work_Center = 'Full Kit');

How to select table with a concatenated column?

I have the following data:
select * from art_skills_table;
+----+------+---------------------------+
| ID | Name | skills |
+----+------+---------------------------|
| 1 | Anna | ["painting","photography"]|
| 2 | Bob | ["drawing","sculpting"] |
| 3 | Cat | ["pastel"] |
+----+------+---------------------------+
select * from computer_table;
+------+------+-------------------------+
| ID | Name | skills |
+------+------+-------------------------+
| 1 | Anna | ["word","typing"] |
| 2 | Cat | ["code","editing"] |
| 3 | Bob | ["excel","code"] |
+------+------+-------------------------+
I would like to write an SQL statement which results in the following table.
+------+------+-----------------------------------------------+
| ID | Name | skills |
+------+------+-----------------------------------------------+
| 1 | Anna | ["painting","photography","word","typing"] |
| 2 | Bob | ["drawing","sculpting","excel","code"] |
| 3 | Cat | ["pastel","code","editing"] |
+------+------+-----------------------------------------------+
I've tried something like SELECT * from art_skills_table LEFT JOIN computer_table ON name. However it doesn't give what I need. I've read about array_cat but I'm having a bit of trouble implementing it.
if the skills column from both tables are arrays, then you should be able to get away with this:
SELECT a.ID, a.name, array_cat(a.skills, c.skills)
FROM art_skills_table a LEFT JOIN computer_table c
ON c.id = a.id
That said, While you used LEFT join in your sample, I think either an INNER or FULL (OUTER) join might serve you better.
First, i wondered why the data are stored in such a model.
Was of the opinion that NoSQL databases lack ability for joins and ...
... a semantic triple would be in the form of subject–predicate–object.
... a Key-value (KV) stores use associative arrays.
... a relational database would be normalized.
A few information about the use case would have helped.
Nevertheless, you can select the data with CONCAT and REPLACE for the desired form.
SELECT art_skills_table.ID, computer_table.name,
CONCAT(
REPLACE(art_skills_table.skills, '}',','),
REPLACE(computer_table.skills, '{','')
)
FROM art_skills_table JOIN computer_table ON art_skills_table.ID = computer_table.ID
The query returns the following result:
+----+------+--------------------------------------------+
| ID | Name | Skills |
+----+------+--------------------------------------------+
| 1 | Anna | {"painting","photography","word","typing"} |
| 2 | Cat | {"drawing","sculpting","code","editing"} |
| 3 | Bob | {"pastel","excel","code"} |
+----+------+--------------------------------------------+
I've used the ID for the JOIN, even though Bob has different values.
The JOIN should probably be done over the name.
JOIN computer_table ON art_skills_table.Name = computer_table.Name
BTW, you need to tell us what SQL engine you're running on.

SQL MariaDB getting data from 7 tables including mm-tables resulting in too many unwanted rows

I'm struggling with getting data from 7 different sql-tables without receiving too many rows.
I have the following (simple) query which retrieves data from 7 different tables:
SELECT h.name, h.address, h.zipcode, h.city, h.association, r.name_de, f.first_name, f.last_name, f.email, p.year, j.name
FROM `tx_gipdhotels_domain_model_hotel` AS h
JOIN `tx_gipdhotels_hotel_jobs_mm` AS hj ON h.uid = hj.uid_local
JOIN `tx_gipdhotels_domain_model_jobs` AS j ON j.uid = hj.uid_foreign
JOIN `tx_gipdhotels_hotel_participations_mm` AS hp ON h.uid = hp.uid_local
JOIN `tx_gipdhotels_domain_model_participations` AS p ON p.uid = hp.uid_foreign
JOIN `tx_gipdhotels_domain_model_region` AS r ON r.uid = h.region
JOIN `fe_users` AS f ON f.uid = h.feuser
As you can see there are two many-to-many-relationships between the tables. These two tables aren't related (except through the h table). Now the problem is that this results in receiving a row for each possible combination of these mm-tables.
Example:
table 1 hotel
|-----------|------------|----------|----------|
| uid | name | jobs | part |
|...........|............|..........|..........|
| 1 | ab | 3 | 2 |
| | | | |
table 2 jobs
|-----------|------------|
| uid | name |
|...........|............|
| 1 | tech |
| 2 | cs |
| 3 | perf |
| | |
table 3 part
|-----------|------------|
| uid | name |
|...........|............|
| 1 | abcd |
| 2 | efgh |
| | |
With this combination (including mm-tables for hotel_jobs and hotel_part) I would receive 6 rows for one hotel only and in each row only one value would differ from another row:
result:
|-----------|------------|----------|----------|
| uid | name | job | part |
|...........|............|..........|..........|
| 1 | ab | tech | abcd |
| 1 | ab | tech | defg |
| 1 | ab | cs | abcd |
| 1 | ab | cs | defg |
| 1 | ab | perf | abcd |
| 1 | ab | perf | defg |
| | | | |
It would be lovely if I could retrieve this data in one single row like the following:
wanted result:
|-----------|------------|--------------------|----------------|
| uid | name | job | part |
|...........|............|....................|................|
| 1 | ab | tech, cs, perf | abcd, efgh |
| | | | |
I can't figure out how to get the wanted result, it exceeds my experience and knowledge so I'm asking you, do you know how to achieve this with a single query?
I've googled quite a bit and I have found the STUFF() method but it's not supported in MariaDB. In some question here on stack someone has done something similar with a cast but I didn't understand it too well and I didn't know how to adapt this to my problem...
I'm using MariaDB and the query will be made from php. There is no way of changing the data structure of the tables.
Any help and explanations would be greatly appreciated.
I hope this will work, try it, if there is any error, we are gonna fix it.
SELECT
h.name,
h.address,
h.zipcode,
h.city,
h.association,
GROUP_CONCAT(DISTINCT p.year SEPARATOR ', '),
GROUP_CONCAT(DISTINCT j.name SEPARATOR ', '),
r.name_de,
f.first_name,
f.last_name,
f.email,
h.tstamp,
h.crdate
FROM tx_gipleasedisturbhotels_domain_model_hotel AS h
JOIN `tx_gipleasedisturbhotels_hotel_jobs_mm` AS hj
ON h.uid = hj.uid_local
JOIN `tx_gipleasedisturbhotels_domain_model_jobs` AS j
ON j.uid = hj.uid_foreign
JOIN `tx_gipleasedisturbhotels_hotel_participations_mm` AS hp
ON h.uid = hp.uid_local
JOIN `tx_gipleasedisturbhotels_domain_model_participations` AS p
ON p.uid = hp.uid_foreign
JOIN `tx_gipleasedisturbhotels_domain_model_region` AS r
ON r.uid = h.region
JOIN `fe_users` AS f
ON f.uid = h.feuser
GROUP BY h.name
ORDER BY h.name ASC
Thanks to #jarlh I found the solution:
SELECT h.name, h.address, h.zipcode, h.city, h.association,
GROUP_CONCAT(DISTINCT p.year SEPARATOR ', '),
GROUP_CONCAT(DISTINCT j.name SEPARATOR ', '),
r.name_de, f.first_name, f.last_name, f.email, h.tstamp, h.crdate
FROM `tx_gipleasedisturbhotels_domain_model_hotel` AS h
JOIN `tx_gipleasedisturbhotels_hotel_jobs_mm` AS hj ON h.uid = hj.uid_local
JOIN `tx_gipleasedisturbhotels_domain_model_jobs` AS j ON j.uid = hj.uid_foreign
JOIN `tx_gipleasedisturbhotels_hotel_participations_mm` AS hp ON h.uid = hp.uid_local
JOIN `tx_gipleasedisturbhotels_domain_model_participations` AS p ON p.uid = hp.uid_foreign
JOIN `tx_gipleasedisturbhotels_domain_model_region` AS r ON r.uid = h.region
JOIN `fe_users` AS f ON f.uid = h.feuser
GROUP BY h.name
ORDER BY h.name ASC
It's a combination of GROUP_CONCAT and GROUP BY. It has to be grouped by the field which you want to have only once. To get all mm-values to one single cell you'll have to use GROUP_CONCAT on those fields in the SELECT statement.
With this query I receive the wanted result. Maybe this will be helpful to someone else as well. ;)

SQL Query manipulation

I have three tables :
BookingNode , Booking AirTrip
AirTrip :
+----+------------+
| ID | Name |
+----+------------+
| 0 | One way |
| 1 | Round trip |
| 2 | Circle |
| 3 | Other |
+----+------------+
When ever we make a booking we store the data as :
BookingNode table
+--------+-------------------+------------+----------------------+
| ID | CustomerGivenName | IPAddress | Email |
+--------+-------------------+------------+----------------------+
| 177022 | xfghfh | 2130706473 | mikehussey#gmail.com |
| 177021 | cfggjfj | 2130706473 | mikehussey#gmail.com |
+--------+-------------------+------------+----------------------+
Booking Table :
+--------+---------------+-----------+------------+------------+
| ID | BookingNodeID | AirTripID | AirLineId | Provider |
+--------+---------------+-----------+------------+------------+
| 181251 | 177020 | 1 | 978 | Jet |
| 181252 | 177021 | 0 | 982 | Go |
| 181253 | 177021 | 0 | 978 | Jet |
+--------+---------------+-----------+------------+------------+
If round trip flight is booked and ProviderID is same then a single entry is done in Booking Table with AirTripID value as 1.(Booking ID : 181251 and Provider Jet )
But if providers are different for both the legs then two entries are done in Booking Table with AirTripID for both entries are one(Booking ID : 181252 and 181253 Provider Go,Jet ).In this case BookingNodeID value being same.
Prob : I have to write a query to get different type of Bookings.(Oneway, RoundTrip,Circle).But when I apply join on AirTripID , it is giving me incorrect results.
How can I write my query to give correct results knowing that BookingNodeID is going to be the same for roundtrip (both entries in Booking Table)
Sample Output
+-------------+---------------+-------------------+------------+
| AirTripName | BookingNodeID | CustomerGivenName | IPAddress |
+-------------+---------------+-------------------+------------+
| TwoWay | 177020 | xfghfh | 2130706473 |
| TwoWay | 177021 | cfggjfj | 2130706473 |
+-------------+---------------+-------------------+------------+
Basically, this code might have an error due to my laziness syntom of data entry. But, the logic of the query is, if b.AirTripID is 0, add extra condition which group by Booking. if result return more than 1 row, is actually 2 way. so AirTripType will become 1, otherwise, remain the same as b.AirTripID. You may copy below on and try fix if theres any error. i believe the logic should work based on your expected result.
select
bd.ID,
bd.CustomerGivenName,
case b.AirTripID
when 1 then 1
when 2 then 2
when 3 then 3
when 0 then
case select BookingNodeID
from Booking
where Booking.BookingNodeID = bd.ID group by BookingNodeID having Count(BookingNodeID)
when 1 then 1
else 0 end as AirTripType,
bd.IPAddress
from BookingNode bd
inner join (select BookingNodeID ,AirTripID from Booking group by BookingNodeID ,AirTripID) as b on b.BookingNodeID = bd.ID
where id=177021
Try This
WITH CTE
AS
(
SELECT
SeqNo = ROW_NUMBER() OVER(PARTITION BY BN.ID ORDER BY B.ID),
B.BookingNodeID,
BN.CustomerGivenName,
BN.IPAddress,
AirTripId = A.ID,
AirTripNm = A.Name
FROM Booking B
INNER JOIN AirTrip A
ON A.ID = B.AirTripID
LEFT JOIN BookingNode BN
ON B.BookingNodeID = BN.id
)
SELECT
C1.SeqNo,
AirTripName = CASE WHEN C2.SeqNo IS NOT NULL
THEN 'Round trip'
ELSE C1.AirTripNm END,
C1.BookingNodeID,
C1.CustomerGivenName,
C1.IPAddress
FROM CTE C1
LEFT JOIN CTE C2
ON C1.BookingNodeID = C2.BookingNodeID
AND C2.SeqNo = 2
WHERE c1.SeqNo = 1
SQL Fiddle Link Here
Select distinct bk.bookingnodeid,cst.customername,ipaddress,
case when count(airtripid)over(partition by bookingnodeid order by bookingnodeid)=2 then 'RoundTrip' else name end As AirTripName
from booking bk
inner join airlinetrip at
on bk.airtripid=at.id
inner join customer cst
on cst.id=bk.bookingnodeid

PostgreSQL Inner Join on the same table + second table?

If this is a stupid question, forgive me, I'm not very familiar with PostgreSQL.
I've collected inventory data from used car dealerships in my area and stored it in a postgreSQL table. I've got a second table with particular details regarding certain makes and models. For example:
The dealership table is structured like so:
-----------------------------------------
| Dealership | Make | Model | Year | ID |
----------------------------------------|
| A | Ford | F250 | 2003 | 1 |
| A | Chevy| Cobalt| 2005 | 2 |
| B | Ford | F250 | 2003 | 1 |
| B | Dodge| Chrgr | 2012 | 3 |
-----------------------------------------
The details table is structured like so:
-----------------------------------------
| ID | DetailA| DetailB| DetailC|
-----------------------------------------
| 1 | data | data | data |
| 2 | data | data | data |
| 3 | data | data | data |
| 4 | data | data | data |
-----------------------------------------
My goal is to retrieve vehicle matches from multiple dealerships and display the appropriate details. In the above example, I would like to see:
-----------------------------------------------------
| Make | Model | Year | DetailA | DetailB | DetailC |
-----------------------------------------------------
| Ford | F250 | 2003 | data | data | data |
-----------------------------------------------------
With this result, I will know that both A and B havea 2003 Ford F250 for sale, and can view the related details of the vehicle.
I've tried many different queries, but most are variations on something like this:
SELECT DISTINCT
dealership_table.make,
dealership_table.model,
dealership_table.year
details_table.detaila,
details_table.detailb,
details_table.detailc
FROM
dealership_table
INNER JOIN
details_table
ON
dealership_table.id = details_table.id
WHERE
dealership_table.dealership = 'A'
OR
dealership_table.dealership = 'B'
However this returns all of the distinct matches from the table where dealership is either A or B. I've tried multiple inner-joins, but I an error complaining details_table is specified multiple times.
If I'm doing something really silly, I apologize. Like I said before, I'm pretty much an SQL noob.
What am I doing wrong? How should I go about retrieving the desired results? Any suggestions, solutions, or advice is greatly appreciated!
You can write:
SELECT dealership_table1.make,
dealership_table1.model,
dealership_table1.year,
details_table.detaila,
details_table.detailb,
details_table.detailc
FROM dealership_table dealership_table1
JOIN dealership_table dealership_table2
ON dealership_table1.make = dealership_table2.make
AND dealership_table1.model = dealership_table2.model
AND dealership_table1.year = dealership_table2.year
JOIN details_table
ON dealership_table.id = details_table.id
WHERE dealership_table1.dealership = 'A'
AND dealership_table1.dealership = 'B'
;
(Note that the FROM dealership_table dealership_table1 and JOIN dealership_table dealership_table2 set up distinct "aliases", so you can use the same table multiple different times in the same query without getting name-conflicts.)
I may be misunderstanding your table layout, but I think you should consider changing to a different structure. Here's what I would propose:
Vehicle:
----------------------------
| ID | Make | Model | Year |
----------------------------
| 1 | Ford | F250 | 2003 |
| 2 | Chevy| Cobalt| 2005 |
| 3 | Dodge| Chrgr | 2012 |
----------------------------
Dealership:
----------------------------
| Dealership | ID | Detail |
----------------------------
| A | 1 | data |
| A | 2 | data |
| B | 1 | data |
| B | 3 | data |
----------------------------
This way you're not storing vehicle information (make/model/year) in more than one place.
Here's how you would write your desired query given the above schema:
SELECT Make, Model, Year, A.Detail, B.Detail, C.Detail
FROM Vehicle V
LEFT OUTER JOIN Dealership A on A.Dealership = 'A' and A.id = V.id
LEFT OUTER JOIN Dealership B on B.Dealership = 'B' and B.id = V.id
LEFT OUTER JOIN Dealership C on C.Dealership = 'C' and C.id = V.id