MYSQL results need to combine tables - mysql

I'm scripting a tool with PHP and I've illustrated a situation with MYSQL. I have two tables which I need to combine to get the results I want.
I came up with this:
SELECT * FROM names, dogs WHERE dog_id = dogs.id;
but when I do this, the results do NOT include the rows where dog_id = NULL. And I need those results too.
TABLE NAMES
| *id* | *name* | *dog_id* |
| 1 | name1 | NULL |
| 2 | name2 | 1 |
| 3 | name3 | NULL |
| 4 | name4 | 2 |
TABLE DOGS
| *id* | *dog* |
| 1 | dog1 |
| 2 | dog2 |
How to get these results:
RESULTS
| *id* | *name* | *dog_id* | *dog* |
| 1 | name1 | NULL | NULL |
| 2 | name2 | 1 | dog1 |
| 3 | name3 | NULL | NULL |
| 4 | name4 | 2 | dog2 |

Use an outer join:
SELECT names.id, names.name, names.dog_id, dogs.dog
FROM names
LEFT JOIN dogs
ON dog_id = dogs.id;

Related

How do I query a three-level structure in two joined tables?

There are two tables,
Table A has a three-level structure that looks like
| id | name | level | up_level_id |
| :------- | :-------: | :------: | ----------:|
| 1 | lv1_name1 | 1 | null |
| 2 | lv1_name2 | 1 | null |
| 3 | lv2_name1 | 2 | 1 |
| 4 | lv2_name2 | 2 | 2 |
| 5 | lv3_name1 | 3 | 3 |
| 6 | lv3_name2 | 3 | 3 |
| 7 | lv3_name3 | 3 | 4 |
| 8 | lv3_name4 | 3 | 4 |
Table B looks like
| amount | org_id |
| -------- | -------- |
| 12,000 | 5 |
| 15,000 | 6 |
| 20,000 | 7 |
| 18,000 | 8 |
Table A and Table B can be joined on A.id=B.org_id, but they are all at the level-3 of Table A(Only level-3 has their amount)
I want to query the top-level name,level-1 name, and the summary amount that looks like
| sum_amount | top_lvl_name |
| -------- | -------- |
| 27,000 | lv1_name1 |
| 38,000 | lv1_name2 |
For Testing, I have already accomplished the query of the level-1 name from the level-3 id in TableA
The SQL is as follows
SELECT name
FROM TableA
WHERE id IN (
SELECT up_level_id
FROM Table A
WHERE id IN (
SELECT up_level_id
FROM Table A
WHERE id=5) --query the id:5's top-level name
);
But when I join these two tables as follows, it goes wrong
SELECT sum(amount) AS sum_amount, name AS top_lvl_name
FROM TableA, TableB
WHERE id = org_id
AND id IN (
SELECT up_level_id
FROM TableA
WHERE id IN (
SELECT up_level_id
FROM TableA
WHERE TableA.id IN(
SELECT org_id
FROM TABLEB
)
)
);
I get nothing as above
What can I do to make this query to be correct?
Thanks for everyone's answer and comment.
Finally, I find it very difficult to query the result as I wish. So, I've come up with a shortcut——create a new table that a three-level structure recorded horizontally, which looks like
| lv1_id | lv2_name | lv2_id | lv2_name | lv3_id | lv3_name |
| :------- | :-------: | :------: | :----------:| :------: | :----------:|
| 1 | lv1_name1 | 3 | lv2_name1 | 5 | lv3_name1 |
| 1 | lv1_name1 | 3 | lv2_name1 | 6 | lv3_name2 |
| 2 | lv1_name2 | 4 | lv2_name1 | 7 | lv3_name3 |
| 2 | lv1_name2 | 4 | lv2_name1 | 8 | lv3_name4 |
As above,I can easily connect two tables

SQL Distinct a column with conditions

I'm working on a query where I need to count distinct CarId row when the column LocationId is not null and get all CarId if its null or 0 but the query that I tried distincts all the CarId even if its null
#LocId int
Select Count(distinct a.CarId) from VehicleDetails a
inner join VehicleDocuments b on a.DocId=b.DocId
left join VehicleShipmentDetails dpg on dpg.VehicleShipmentId= b.VehicleShipmentId
where b.LogicalDelete=0 and a.LogicalDelete=0
and (dpg.LocationId= #LocId or dpg.LocationId= 0 or dpg.LocationId is null)
| ID | CarId | LocationId | DateCreated |
|------+----------------+-----------------+---------------|
| 1 | 1 | 5 | 02/03/2019 |
| 2 | 2 | null | 01/14/2019 |
| 3 | 2 | 0 | 02/03/2019 |
| 4 | 2 | 5 | 12/30/2018 |
| 5 | 4 | 3 | 01/10/2019 |
| 6 | 3 | 5 | 02/14/2019 |
| 7 | 2 | 5 | 03/13/2019 |
Desired output:
| ID | CarId | LocationId | DateCreated |
+------+----------------+-----------------+---------------+
| 1 | 1 | 5 | 02/03/2019 |
| 2 | 2 | null | 01/14/2019 |
| 3 | 2 | 0 | 02/03/2019 |
| 4 | 2 | 5 | 03/13/2019 |
| 5 | 4 | 3 | 01/10/2019 |
| 6 | 3 | 5 | 02/14/2019 |
Current Output
| ID | CarId | LocationId | DateCreated |
+------+----------------+-----------------+---------------+
| 1 | 1 | 5 | 02/03/2019 |
| 2 | 2 | 5 | 01/14/2019 |
| 3 | 4 | 3 | 01/10/2019 |
| 4 | 3 | 5 | 02/14/2019 |
Im getting a count of 4 but i needed to have 6 as the Count
EDIT: My goal is to remove the row to Distinct CarId if the value of the LocationId is Null or 0 but on my Current code, It distincts all CarId that is null,0 and equals to #LocId
You can query something like this, replace your_table by your actual set of data.
SELECT ID, CardId, LocationId, DateCreated
FROM your_table as T
WHERE NOT EXISTS (SELECT *
FROM your_table as T1
WHERE T.ID > T1.ID AND T.CarID = T1.CarID)
In SQL, you can use the statement CASE to manage conditions (just like the "if then else" in other programming languages). In your case this function could help because you have two differents cases to handle.

Query equivalent to two group by's without a subquery?

I'm trying to run a report on User ACL's. We use MYSQL and my we're prohibited from using subqueries for performance reasons. The goal is to turn this:
--------------------------------
| userName | folderID | roleID |
--------------------------------
| gronk | 1 | 1 |
| gronk | 2 | 2 |
| gronk | 4 | 2 |
| tbrady | 1 | 2 |
| jedelman | 1 | 1 |
| jedelman | 2 | 1 |
| mbutler | 1 | 2 |
| mbutler | 2 | 2 |
| bill | 1 | 3 |
| bill | 2 | 3 |
| bill | 3 | 3 |
| bill | 4 | 3 |
--------------------------------
Into this:
------------------------
| Lowest Role | Number |
------------------------
| 1 | 2 |
| 2 | 2 |
| 3 | 1 |
------------------------
I can see how to do it with a subquery. The inner query would do a group by on userName with a min(roleID). Then the outer query would do a group by on the lowest role and count(*). But I can't see how to do it without a subquery.
Also, if it helps I created a SQL Fiddle that has the data above.
I found a solution using a left join:
select UFM.roleID, count(distinct UFM.userName)
from UserFolderMembership UFM
left join UserFolderMembership UFM2 on
UFM.userName = UFM2.userName and
UFM.roleID > UFM2.roleID
where
UFM2.userName is null
group by
UFM.roleID

MySql query for displaying rows as column dyanmically

I've to join three tables the resultant output will be like this
+---------------+--------------+-------------+-------------+
| Category_Name | English | French | German |
+---------------+--------------+-------------+-------------+
| Clothing | english_name | french_name | german_name |
| Electronics | NULL | NULL | NULL |
| Ornaments | NULL | NULL | NULL |
+---------------+--------------+-------------+-------------+
Following is my table_structure
tbl_category
+----+---------------+
| id | category_name |
+----+---------------+
| 1 | Clothing |
| 2 | Electronics |
| 3 | Ornaments |
+----+---------------+
tbl_languages
+----+----------+
| id | language |
+----+----------+
| 1 | English |
| 2 | French |
| 3 | German |
+----+----------+
tbl_languages_data
+----+-------------+-------------+---------------+
| id | language_id | category_id | category_name |
+----+-------------+-------------+---------------+
| 1 | 1 | 1 | english_name |
| 2 | 2 | 1 | french_name |
| 3 | 3 | 1 | german_name |
+----+-------------+-------------+---------------+
I've two questions.
1. Are these relations are valid or there can be some other way to avoid deadlocks
2. What will be the query for getting this result.
Note: The output should be dynamic as I've to add more data to tbl_language.
Should be something along the lines of:
SELECT Category_Name
MAX(CASE when lan.language_id = 1 THEN lan.category_name END) as 'English',
MAX(CASE when lan.language_id = 2 THEN lan.category_name END) as 'French',
MAX(CASE when lan.language_id = 3 THEN lan.category_name END) as 'German'
FROM tbl_category cat
RIGHT JOIN tbl_languages_data lan ON cat.id = lan.category_id
GROUP BY Category_Name
NOTE: Did not notice your edit, I don't think you will be able to dynamically add columns to the expected result. Please somebody correct me if I am wrong.
I would omit the last column Category Name from tbl_languages_data. And refer the Language_id as an number, this way you will compare the two indexes with the same datatype (int to int). This will be faster than a string with an int. This will result in the following query:
SELECT cat.category_name
, lang.language
FROM tbl_category AS cat
LEFT JOIN tbl_languages_data AS lang_data
ON lang_data.category_id = cat.id
LEFT JOIN tbl_languages AS lang
ON lang_data.language_id = lang.id
Note that this is different than your expected result set. The three languages are now translated into one column. And here is your table design:
tbl_category
+----+---------------+
| id | category_name |
+----+---------------+
| 1 | Clothing |
+----+---------------+
| 2 | Electronics |
+----+---------------+
| 3 | Ornaments |
+----+---------------+
tbl_languages
+----+----------+
| id | language |
+----+----------+
| 1 | English |
+----+----------+
| 2 | French |
+----+----------+
| 3 | German |
+----+----------+
tbl_languages_data
+----+-------------+-------------+
| id | language_id | category_id |
+----+-------------+-------------+
| 1 | 1 | 1 |
+----+-------------+-------------+
| 2 | 2 | 1 |
+----+-------------+-------------+
| 3 | 3 | 1 |
+----+-------------+-------------+

Get MAX value rows from second table on join

I have 2 tables, first one keeps names and second is related to it on in = cid. I need to get only the highest date row from second table, once. Please look below for clearer explanation:
table1 a
+----+-------+
| id | name |
+----+-------+
| 1 | name1 |
| 2 | name2 |
| 3 | name3 |
| 4 | name4 |
| 5 | name5 |
+----+-------+
table2 c
+----+-------+------------+
| id | cid | galiojaiki |
+----+-------+------------+
| 1 | 1 | 2015-04-30 |
| 2 | 1 | 2015-09-30 |
| 3 | 1 | 2015-03-10 |
| 4 | 2 | 2015-06-30 |
| 5 | 2 | 2015-07-30 |
| 6 | 3 | 2015-05-11 |
| 7 | 4 | 2015-05-10 |
+----+-------+------------+
Expected result:
+------------+-------+
| galiojaiki | name |
+------------+-------+
| 2015-09-30 | name1 |
| 2015-07-30 | name2 |
| 2015-05-11 | name3 |
| 2015-05-11 | name4 |
+------------+-------+
My query:
SELECT a.*, c.galiojaiki FROM `y6fdt_igym_abonementai` AS a
INNER JOIN
(
SELECT max(galiojaiki) FROM y6fdt_igym_sutartys
) c
on c.cid= a.id
GROUP BY c.abonementas
How anout a simple aggregation using MAX?
Something like
SELECT a.name,
MAX(b.galiojaiki) as galiojaiki
FROM `y6fdt_igym_abonementai` AS a INNER JOIN
`y6fdt_igym_sutartys` as b ON a.ID = b.CID
GROUP BY a.name
SQL Fiddle DEMO