I have a table displaying on my website with a list of projects. The SQL statement below pulls in each project and converts the ###_id columns to the ###_name in another table. So far so good.
The problem I have is that this is requiring all fields in a row in the projects table to be filled out. If, for example, the project row has no value for 'proj_industry_id' then the project won't display here at all.
I've tried removing the 'AND' for each match-up in the WHERE statement and separating them with commas, but it errors out.
I've also checked SQL docs and can't seem to find my way to an answer over there.
Any ideas on how I can get my statement to still match up the id with the name when I have one, but still show the record when I don't?
Thanks!
$sql = "SELECT
projects.*,
engagement_types.eng_type_name AS eng_type,
users.user_full_name AS username,
industries.industry_name AS industry_name,
categories.category_name AS category_name,
geographies.geo_name AS geo_name,
status.status_name AS status_name
FROM
projects,
engagement_types,
users,
industries,
categories,
geographies,
status
WHERE
projects.proj_eng_type_id = engagement_types.id
AND projects.proj_lead_id = users.id
AND projects.proj_industry_id = industries.id
AND projects.proj_category_id = categories.id
AND projects.proj_geo_id = geographies.id
AND projects.proj_status_id = status.id
AND projects.proj_geo_id = '$selected_geo_id'";
*****EDIT******
Here is the final correct code from the solution below using multiple left joins!
SELECT
projects.*,
engagement_types.eng_type_name AS eng_type,
users.user_full_name AS username,
industries.industry_name AS industry_name,
categories.category_name AS category_name,
geographies.geo_name AS geo_name,
status.status_name AS status_name
FROM
projects
LEFT JOIN engagement_types ON projects.proj_eng_type_id = engagement_types.id
LEFT JOIN users ON projects.proj_lead_id = users.id
LEFT JOIN industries ON projects.proj_industry_id = industries.id
LEFT JOIN categories ON projects.proj_category_id = categories.id
LEFT JOIN geographies ON projects.proj_geo_id = geographies.id
LEFT JOIN status ON projects.proj_status_id = status.id
GROUP BY
proj_start_date
sounds like your have to look at "LEFT JOIN" https://www.w3schools.com/sql/sql_join_left.asp
Otherwise you miss the left part of the green circle.
Related
SELECT stores.ID, store_info.display_name, store_info.address,store_info.phone,
IFNULL(
GROUP_CONCAT(DISTINCT storeBrands.display_name ORDER BY storeBrands.name),
GROUP_CONCAT(chainBrands.display_name ORDER BY chainBrands.name)
) AS brands,
IFNULL(
GROUP_CONCAT(DISTINCT storeFilters.name ORDER BY storeFilters.name),
GROUP_CONCAT(DISTINCT chainFilters.name ORDER BY chainFilters.name)
) AS filters
FROM stores
LEFT JOIN store_info ON stores.ID = store_info.storeID
LEFT JOIN store_brands ON stores.ID = store_brands.store
LEFT JOIN chain_brands ON stores.chainID = chain_brands.chain
LEFT JOIN brands AS storeBrands ON store_brands.brand = storeBrands.ID
LEFT JOIN brands AS chainBrands ON chain_brands.brand = chainBrands.ID
LEFT JOIN store_filters ON stores.ID = store_filters.store
LEFT JOIN chain_filters ON stores.chainID = chain_filters.chain
LEFT JOIN filters AS storeFilters ON store_filters.filter = storeFilters.ID
LEFT JOIN filters AS chainFilters ON chain_filters.filter = chainFilters.ID
WHERE stores.city = 1
GROUP BY stores.ID
I have updated this question because I have solved the initial problem myself, but there's still one more question:
How can I improve on this?
I feel like I've made a lot of progress already. I have gone from doing a union with subqueries, to doing a single query with subqueries, to improving my joins up to the point where I don't need to do a subquery for each row anymore.
However, it still feels like it could be better. I'm very insecure about my joins.
Does anyone have tips of improvement here?
The goal:
I want this query to get results from a hierarchy. We have 'parents' (chains) that share the same brands and filters (and other things) as their own children(stores). The idea is for the 'child' to inherit the parent's settings as a fallback, but completely ignores it when it starts setting its own data.
So, basically, with one query, you want "either this data or that data", never both. One or the other. (Another reason why UNIONwon't really fit)
If you want the chain's only when the store has none, formulate a UNION. One operand of the UNION joins the master data to the store data, while the other operand--instantiated only when the store has none--joins the master data to the chain data. That's what one uses a UNION for: "I sometimes want these, and I sometimes want those."
I managed to fix this issue myself, also making it way more efficient, removing most subqueries!
SELECT stores.ID, store_info.display_name, store_info.address,store_info.phone,
IFNULL(
GROUP_CONCAT(DISTINCT storeBrands.display_name ORDER BY storeBrands.name),
GROUP_CONCAT(chainBrands.display_name ORDER BY chainBrands.name)
) AS brands,
IFNULL(
GROUP_CONCAT(DISTINCT storeFilters.name ORDER BY storeFilters.name),
GROUP_CONCAT(DISTINCT chainFilters.name ORDER BY chainFilters.name)
) AS filters
FROM stores
LEFT JOIN store_info ON stores.ID = store_info.storeID
LEFT JOIN store_brands ON stores.ID = store_brands.store
LEFT JOIN chain_brands ON stores.chainID = chain_brands.chain
LEFT JOIN brands AS storeBrands ON store_brands.brand = storeBrands.ID
LEFT JOIN brands AS chainBrands ON chain_brands.brand = chainBrands.ID
LEFT JOIN store_filters ON stores.ID = store_filters.store
LEFT JOIN chain_filters ON stores.chainID = chain_filters.chain
LEFT JOIN filters AS storeFilters ON store_filters.filter = storeFilters.ID
LEFT JOIN filters AS chainFilters ON chain_filters.filter = chainFilters.ID
WHERE stores.city = $cityID
GROUP BY stores.ID"
Attempting to display all proposals in the system as long as they satisfy the following conditions:
the source must be supervisor
the status_code in the record table must not be 8 or 3
I have attempted a number of way in trying to make this work but I keep getting different data back which is not what I want.
The problem is how the tables have been set up. In theory a proposal can be applied for by a student and if that happens a record is automatically added to the 'record' table with a status set to '6' for pending. This status is then changed a number of times throughout the application process.
What I need is to show the users all proposals which have not been taken. The status codes to indicate this is '3' (accepted by a student so another student cannot take it) and '8' (not available).
NOTE: not all proposals may have a record in this table (a student has not applied for them)
This is the query so far which satisfies the first condition of being a "supervisor"
SELECT p.proposal_id, p.proposal_title,
p.description, u.user_record_id, u.forename,
u.surname, c.course_title, r.*,
GROUP_CONCAT(DISTINCT t.tag_title) AS tags
FROM proposal p
LEFT JOIN user u on u.user_record_id = p.user_record_id
LEFT JOIN proposal_tags pt on pt.proposal_id = p.proposal_id
LEFT JOIN tag_details t on t.tag_code = pt.tag_code
LEFT JOIN course_details c on c.course_code = p.course_code
LEFT JOIN record r on r.proposal_id = p.proposal_id
WHERE p.source = "Supervisor"
GROUP BY p.proposal_id
My attempt at getting it to display all records which are available:
SELECT p.proposal_id, p.proposal_title,
p.description, u.user_record_id, u.forename,
u.surname, c.course_title, r.*,
GROUP_CONCAT(DISTINCT t.tag_title) AS tags
FROM proposal p
LEFT JOIN user u on u.user_record_id = p.user_record_id
LEFT JOIN proposal_tags pt on pt.proposal_id = p.proposal_id
LEFT JOIN tag_details t on t.tag_code = pt.tag_code
LEFT JOIN course_details c on c.course_code = p.course_code
LEFT JOIN record r on r.proposal_id = p.proposal_id
WHERE p.source = "Supervisor"
AND (r.status_code != 3 OR r.status_code !=8)
GROUP BY p.proposal_id
The above query still returns proposals with the status code 3 and it fails to display any proposals which have yet not been applied for.
SQLFiddle Generated: http://sqlfiddle.com/#!9/b89a9/1/0
Any help would be much appreciated guys! Thank you.
Turned out I was missing a OR statement to achieve my goal.
To get the end result i needed, the query was modified to:
SELECT p.proposal_id, p.proposal_title, p.description, u.user_record_id, u.forename, u.surname, c.course_title, r.*, GROUP_CONCAT(DISTINCT t.tag_title) AS tags FROM proposal p
LEFT JOIN user u on u.user_record_id = p.user_record_id
LEFT JOIN proposal_tags pt on pt.proposal_id = p.proposal_id
LEFT JOIN tag_details t on t.tag_code = pt.tag_code
LEFT JOIN course_details c on c.course_code = p.course_code
LEFT JOIN record r on r.proposal_id = p.proposal_id
WHERE p.source = "Supervisor"
AND (r.status_code not in (3,8) OR r.status_code IS NULL)
GROUP BY p.proposal_id
Successfully brings back all proposals which are available, are from the supervisor and those which have no record in the 'record' table.
Thank you to everyone who helped
SELECT distinct t1.vssyspackageid,CA.rAmount as Amount,Curr.vsShortCode AS Currency
from tblPrograms
INNER JOIN tblProgramsAndPackages ON tblPrograms.vsSysProgramId = tblProgramsAndPackages.vsSysProgramId
inner join tblPackages t1 on tblProgramsAndPackages.iPackageId=t1.iPackageId
right join tblPkgContractAwardDetails as CA on CA.iPackageId=t1.iPackageId
join tblCurrencies as Curr on CA.iCurrency =Curr.iCurrencyId
where tblPrograms.vsSysProgramId='JICA'
group by t1.vssyspackageid,CA.rAmount,Curr.vsShortCode
if which package assigned to Contractor Award Detail then it will show in one column.
Example: GWSSP/01,GWSSP/02 then after it it shows total package in next column.
I'm not sure exactly what you are wanting as your question is a little vague, but I'm guessing that you want a single row for the specified Package that will show the sum of the Amount column. This is what I can understand from your question anyway!
SELECT DISTINCT t1.vssyspackageid,
SUM(CA.rAmount) AS TotalAmount,
Curr.vsShortCode AS Currency
FROM tblPrograms
INNER JOIN tblProgramsAndPackages ON tblPrograms.vsSysProgramId =
tblProgramsAndPackages.vsSysProgramId
INNER JOIN tblPackages AS t1 ON tblProgramsAndPackages.iPackageId =
t1.iPackageId
RIGHT JOIN tblPkgContractAwardDetails AS CA ON CA.iPackageId =
t1.iPackageId
JOIN tblCurrencies AS Curr ON CA.iCurrency =
Curr.iCurrencyId
WHERE tblPrograms.vsSysProgramId = 'JICA'
AND t1.[YOUR_COLUMN_NAME_HERE] = 'GWSSP/01'
GROUP BY t1.vssyspackageid,
Curr.vsShortCode
Just a few things to note:
I don't know the column name in the tblPackages table that the values such as 'GWSSP/01' belongs, so I have left that for you to fill in.
You will still get multiple rows if there are multiple currencies for your package, you will have to remove the Curr.vsShortCode from your Select and Group By clauses if that is the case.
I also tided up your code a bit because it was quite messy and hard to understand as well as using multiple standards and short-cuts!
Information
Is there a way that I can retrieve two bits of information from another(same) table twice in one LEFT JOIN?
Attempt
Below is the SQL query I tried to put together in hopes would work. I hope you can see what I am trying to do from it.
SELECT cards.*, list.name FROM cards
LEFT JOIN list ON cards.main = list.id AS main_name
AND cards.enemy = list.id AS enemy_name
WHERE cards.id = 1
As you can see above I am trying to retrieve the names of two values cards.main AND cards.enemy from the list table.
Thank you, and any questions will be answered asap!
You have to join the list-table twice:
SELECT cards.*, main_name.name, enemy_name.name
FROM cards
LEFT JOIN list AS main_name ON cards.main = main_name.id
LEFT JOIN list AS enemy_name ON cards.enemy = enemy_name.id
WHERE cards.id = 1
I was desperately trying harder and harder to get this thing done but didn`t yet succeed. I am getting repeated values when i run this query.
select
tbl_ShipmentStatus.ShipmentID
,Tbl_Contract.ContractID,
Tbl_Contract.KeyWinCountNumber,
Tbl_Item.ItemName,
Tbl_CountryFrom.CountryFromName,
Tbl_CountryTo.CountryToName,
Tbl_Brand.BrandName,
Tbl_Count.CountName,
Tbl_Seller.SellerName,
Tbl_Buyer.BuyerName,
Tbl_Contract.ContractNumber,
Tbl_Contract.ContractDate,
tbl_CountDetail.TotalQty,
tbl_CostUnit.CostUnitName,
tbl_Comission.Payment,
tbl_Port.PortName,
Tbl_Contract.Vans,
tbl_Comission.ComissionPay,
tbl_Comission.ComissionRcv,
tbl_CountDetail.UnitPrice,
tbl_Comission.ComissionRemarks,
tbl_CountDetail.Amount,
tbl_LCStatus.LCNumber,
tbl_ShipmentStatus.InvoiceNumber,
tbl_ShipmentStatus.InvoiceDate,
tbl_ShipmentStatus.BLNumber,
tbl_ShipmentStatus.BLDate,
tbl_ShipmentStatus.VesselName,
tbl_ShipmentStatus.DueDate
from tbl_ShipmentStatus
inner join tbl_LCStatus
on
tbl_LCStatus.LCID = tbl_ShipmentStatus.LCStatusID
inner join Tbl_Contract
on
tbl_LCStatus.ContractID = Tbl_Contract.ContractID
inner join Tbl_CountDetail
on Tbl_Contract.ContractID = Tbl_CountDetail.ContractId
inner join tbl_Comission
on
tbl_Comission.ContractID = Tbl_Contract.ContractID
inner join Tbl_Item
on
Tbl_Item.ItemID = Tbl_Contract.ItemID
inner join Tbl_Brand
on Tbl_Brand.BrandID = Tbl_Contract.BrandID
inner join Tbl_Buyer
on Tbl_Buyer.BuyerID = Tbl_Contract.BuyerID
inner join Tbl_Seller
on Tbl_Seller.SellerID = Tbl_Contract.SellerID
inner join Tbl_CountryFrom
on Tbl_CountryFrom.CountryFromID = Tbl_Contract.CountryFromID
inner join Tbl_CountryTo
on
Tbl_CountryTo.CountryToID = Tbl_Contract.CountryToID
inner join Tbl_Count
on
Tbl_Count.CountID = Tbl_CountDetail.CountId
inner join tbl_CostUnit
on tbl_Comission.CostUnitID = tbl_CostUnit.CostUnitID
inner join tbl_Port
on tbl_Port.PortID = tbl_Comission.PortID
where tbl_LCStatus.isDeleted = 0
and tbl_ShipmentStatus.isDeleted =0
and tbl_LCStatus.isDeleted = 0
and Tbl_CountDetail.isDeleted = 0
and Tbl_Contract.isDeleted = 0
and tbl_ShipmentStatus.LCStatusID = 5
I have also attached a picture of my result set of rows.
Any suggestions why this is happening would really be appreciable.
Result Set
Typically this happens when you have an implicit partial cross join (Cartesian product) between two of your tables. That's what it looks like to me here.
This happens most often when you have a many-to-many relationship. For example, if a single Album allows both multiple Artists and multiple Songs and the only relationship between Artists and Songs is Album, then there's essentially a many-to-many relationship between Artists and Songs. If you select from all three tables at once you're going to implicitly cross join Artists and Songs, and this may not be what you want.
Looking at your query, I see many-to-many between Tbl_CountDetail and tbl_Comission through Tbl_Contract. Try eliminating one of those joins to test to see if the behavior disappears.
Try using the DISTINCT keyword. It should solve your issue
Select DISTINCT ....
Wait as far as I can see your records are not duplicates.
HOWEVER
Notice the CountName column and Shipment ID column
The combination is unique for every row. Hence the values are unique as far as I can see. Try not selecting CountName.
Well if you have distinct rows its not a duplication problem. The issue is during the join a combination is occurring you don't want it to duplicating the results.
Either don't select CountName or you have a mistake in your data.
Only one of those rows should be true either 6 with Count2 or 6 with Count1. Likewise for 7. The fact that your getting both when your not supposed to indicates a logic mistake