mysql sub-query cannot refer top table - mysql

I have below table/column arrangement in MySQL database. (FK denotes foreign key)
SCHEDULES [id(INT), next_date(DATE), notification_id(FK)]
NOTIFICATIONS [id(INT), col_1(...), col_2(...), ...]
NOTIFICATION_LINES [id(INT), notification_id(FK), no_of_days(INT)]
Relationships:
Multiple SCHEDULES can have same NOTIFICATION (i.e n:1) whereas One NOTIFICATION can have multiple NOTIFICATION_LINES.
Sample Data set
SCHEDULES
-------------------------------------
| id | next_date | notification_id |
-------------------------------------
| 1 | 07-08-2017 | N01 |
| 2 | 18-08-2017 | N01 |
-------------------------------------
NOTIFICATIONS
-----------------------
| id | col_1 | col_2 |
-----------------------
| N01 | AA | XX |
| N02 | BB | YY |
-----------------------
NOTIFICATION_LINES
--------------------------------------
| id | notification_id | no_of_days |
--------------------------------------
| 1 | N01 | 14 |
| 2 | N01 | 5 |
-------------------------------------
Requirement:
I need to get the MAX(no_of_days) of a particular SCHEDULE.
I used below subquery:
SELECT sch.schedule_id, sch.notification_id, x.max_no_of_days
FROM SCHEDULES sch,
(SELECT nt.notification_id, max(lt.no_of_days) AS max_no_of_days
FROM NOTIFICATION_LINES lt, NOTIFICATIONS nt
WHERE lt.parent_id = nt.id
AND nt.notification_id = sch.notification_id) x
WHERE sch.notification_id = x.notification_id;
and it returns:
#1054 - Unknown column 'sch.notification_rule' in 'where clause'
If I substitute sch.notification_rule with a value, it returns correct result.
--------------------------------------------------------
| id | schedule_id | notification_id | max_no_of_days |
--------------------------------------------------------
| 1 | 1 | N01 | 14 |
--------------------------------------------------------
If I cannot use parent query's alias, if anyone can let me know even a different SQL, I would be thankful to you.

Related

MySql get Count, Value from 3rd Table with reference from 1st table

i would like to get the Count value from the 3rd table... 1st table has reference id to 2nd table, 2nd table has reference id of 3rd table... in 3rd table has the value... that i need to count...
Table struct:
table1: tbl_rack
+------------+---------+--------+
| rack_id | site_id | status |
+------------+---------+--------+
| R-642 | ST5 | Y |
| R-307 | ST6 | Y |
| R-57 | ST7 | Y |
| 390/6 | ST8 | Y |
| 9706 | ST11 | Y |
table2: tbl_site
+---------+-------------+-----------+
| site_id | customer_id | region_id |
+---------+-------------+-----------+
| ST5 | CM8 | RM4 |
| ST6 | CM8 | RM8 |
| ST7 | CM10 | RM2 |
| ST8 | CM11 | RM12 |
| ST11 | CM8 | RM10 |
table3: tbl_customer
+-------------+----------------------+---------------+
| customer_id | customer_name | customer_type |
+-------------+----------------------+---------------+
| CM8 | LIVI-IN | MODERATE |
| CM10 | PEPE | HIGH |
| CM11 | SANDER | LOW |
| CM12 | TOASTER | MODERATE |
I want to count each customers contains how many Racks where ranks status is 'Y'
expected Result1:
Customer No.of Racks
LIVI-IN 3
OTHERS 2
expected Result2:
Customer Type No.of Racks
Moderate 3
High 1
Low 1
Please, follow below SQL query:
select C.customer_name as 'Customer', count(*) as 'No.of Racks'
from tbl_customer C
left outer join tbl_site TS on TS.customer_id = C.customer_id
left outer join tbl_rack TR on TR.site_id = TS.site_id
group by C.customer_name
order by C.customer_name

SQL INNER JOIN with MULTIPLE CONDITION in CodeIgniter

I have the following table.
table cards
------------------------------------
| card_no | approval_code |
------------------------------------
| 999999xxxxxx1234 | 111111 |
----------------------------------
| 888888xxxxxx5678 | 222222 |
------------------------------------
| 777777xxxxxx9012 | 333333 |
-----------------------------------
| 666666xxxxxx3456 | 444444 |
-----------------------------------
table transactions
---------------------------------------------
| trans_id | pan | approval code | amount |
---------------------------------------------
| A1 | 9012 | 333333 | 9.9|
----------------------------------------------
| A2 | 9012 | 333333 | 10.0|
----------------------------------------------
| B1 | 1233 | 111111 | 11.0|
----------------------------------------------
| B2 | 1234 | 111111 | 12.0|
----------------------------------------------
| C1 | 5678 | 222222 | 13.0|
----------------------------------------------
| C2 | 5678 | 444444 | 13.0|
----------------------------------------------
My output is to display 3 types of output.
1st output is to display matched data and 2nd output is to display unmatched data from cards table and 3rd output is to display unmatched data from transactions table. the following are my codes. transaction table only store pan (last 4 digit from card_no) therefore i need to substr to get the last 4 digit.
for matched data:
$query = $this->db->select (array(
'c.card_no', 'c.approval_code',
't.trans_id','t.pan','t.approval_code','amount'
),false)
-> join('transactions t','t.approval_code = c.approval_code','inner')
-> join('transactions t','t.pan = substr(c.card_no,12)','inner')
-> get('cards c');
for unmatched data from cards table;
$query = $this->db->select (array(
'c.card_no', 'c.approval_code',
't.trans_id','t.pan','t.approval_code','amount'
),false)
-> join('transactions t','t.approval_code != c.approval_code','inner')
-> join('transactions t','t.pan != substr(c.card_no,12)','inner')
-> where ('t.approval_code' IS NULL,NULL,FALSE)
-> where ('t.pan' IS NULL,NULL,FALSE)
-> get('cards c');
for unmatched data from transactions table;
$query = $this->db->select (array(
'c.card_no', 'c.approval_code',
't.trans_id','t.pan','t.approval_code','amount'
),false)
-> join('cards c','t.approval_code = c.approval_code','inner')
-> join('cards c','t.pan != substr(c.card_no,12)','inner')
-> where ('c.approval_code' IS NULL,NULL,FALSE)
-> where ('c.card_no' IS NULL,NULL,FALSE)
-> get('cards c');
Both seems not working.. hmmmm
my expected outputs are:
output matched data
--------------------------------------------------------
| card_no | approval_code | trans_id | amount |
--------------------------------------------------------
| 999999xxxxxx1234 | 111111 | B2 | 12.0 |
-------------------------------------------------------
| 888888xxxxxx5678 | 222222 | C1 | 13.0 |
--------------------------------------------------------
| 777777xxxxxx9012 | 333333 | A1 | 9.9 |
-------------------------------------------------------
| 777777xxxxxx9012 | 333333 | A2 | 10.0 |
-------------------------------------------------------
output unmatched data from table cards
------------------------------------
| card_no | approval_code |
------------------------------------
| 666666xxxxxx3456 | 444444 |
-----------------------------------
output unmatched data from table transactions
---------------------------------------------
| trans_id | pan | approval code | amount |
---------------------------------------------
| B1 | 1233 | 111111 | 11.0|
----------------------------------------------
| C2 | 5678 | 444444 | 13.0|
----------------------------------------------
To get unmatched data from cards table replace join by right join. And for unmatched data from transactions table replace join by left join in respective queries.

Update column value by querying concatenated column values with another table value

I have two tables as below. The Id column value in both the tables mentioned below is auto-incremented.
Group
+----+-----------+----------------+
| Id | GroupId | GroupName |
+----+-----------+----------------+
| 1 | 10 | Grp1#abc.com |
| 2 | 20 | Grp2#abc.com |
| 3 | 30 | Grp3#xyz.com |
| 4 | 40 | Grp4#def.com |
+----+-----------+----------------+
Customer
+---+-----------------+------------+----------+---------------+
| Id | GroupAliasName | Domain | GroupId | CustomerName |
+---+-----------------+------------+----------+---------------+
| 1 | Grp1 | abc.com | null | Cust1 |
| 2 | Grp2 | abc.com | null | Cust2 |
| 3 | Grp3 | xyz.com | null | Cust3 |
| 4 | Grp4 | def.com | null | Cust4 |
+---+-----------------+------------+----------+---------------+
Now from Customer table 'GroupAliasName' and 'Domain' when concatenated as 'GroupAliasName#Domain' is equivalent to 'GroupName' in Group table.
Using the concatenated value from Customer table, I need to pull the 'GroupId' from the Group table and populate the same in Customer table's 'GroupId' as below
Customer
+----+----------------+------------+----------+---------------+
| Id | GroupAliasName | Domain | GroupId | CustomerName |
+----+----------------+-----------+---------+-----------------+
| 1 | Grp1 | abc.com | 10 | Cust1 |
| 2 | Grp2 | abc.com | 20 | Cust2 |
| 3 | Grp3 | xyz.com | 30 | Cust3 |
| 4 | Grp4 | def.com | 40 | Cust4 |
+----+----------------+------------+----------+---------------+
The query which I tried is as below
UPDATE Customer SET GroupId =
(SELECT GroupId FROM Group G
WHERE GroupName =
(SELECT CONCAT(GroupAliasName, '#', Domain) AS GroupName
FROM Customer
WHERE Domain IS NOT NULL) AND G.GroupName = GroupName);
But I get error as 'Subquery returns more than 1 row'.
Please suggest or provide your inputs.
Try this:
update customer as cust
inner join `group` grp on concat(cust.groupaliasname, '#', cust.domain) = grp.groupname
set cust.groupId = grp.groupId;
Try with somethings like this
UPDATE Customer as c
INNER JOIN Group as g on ( CONCAT(c.GroupAliasName, '#', c.Domain) = g.GroupName)
SET c.GroupId = g.GroupId;

SQL Query design involving multiple tables

I am working on a MYSQL query design that, in my opinion, is pretty hard. I'm not experienced in SQL, so I found it really dificult. The point is:
I've got the 'ordertable' table which stores the order of some codes (AA, BB, CC..). In another table, 'AllTables' I store the name of a table associated to a code (AA -> tableA). Finally, 'tableA' table stores some data of diferent units (unit1, unit2...).
CASE 1.
ordertable : Order of codes is given like:
+----------------+------+
| split_position | code |
+----------------+------+
| 1 | AA |
| 2 | BB |
| 3 | CC |
| 4 | DD |
+----------------+------+
CASE 2.
ordertable Order of codes is given like:
+-------+------+------+------+------+
| id | pos1 | pos2 | pos3 | pos4 |
+-------+------+------+------+------+
| unit1 | AA | BB | DD | CC |
| unit2 | CC | BB | AA | DD |
| unit3 | BB | DD | CC | AA |
+-------+------+------+------+------+
In Case 2 we can also find special codes like 'var15':
+-------+------+-------+------+-------+
| id | pos1 | pos2 | pos3 | pos4 |
+-------+------+-------+------+-------+
| unit1 | AA | var15 | DD | var37 |
| unit2 | CC | BB | AA | DD |
+-------+------+-------+------+-------+
In case we find something similar to 'var'+ number the associated table is always the same: 'variable', where de 'id' is the number of the code 'var37' -> id = 37.
variable
+-----+------------+------+--------+
| id | name | time | active |
+-----+------------+------+--------+
| 15 | Pedro | 5 | 1 |
| 17 | Maria | 4 | 1 |
+-----+------------+------+--------+
Info of tables:
AllTables
+------+------------+
| code | name |
+------+------------+
| AA | tableA |
| BB | tableB |
| CC | tableC |
| DD | tableD |
+------+------------+
tableA
+-------+------+------+--------+
| id | name | time | active |
+-------+------+------+--------+
| unit1 | Mark | 11 | 1 |
| unit2 | Jame | 20 | 0 |
+-------+------+------+--------+
tableB
+-------+------+------+--------+
| id | name | time | active |
+-------+------+------+--------+
| unit1 | Mari | 44 | 1 |
| unit3 | nam2 | 57 | 1 |
+-------+------+------+--------+
Given an id='unit1', I'm expecting the next:
Result
+----------------+------+-------+-------+--------+
| split_position | code | name | time | active |
+----------------+------+-------+-------+--------+
| 1 | AA | Mark | 11 | 1 |
| 2 | BB | Mari | 44 | 1 |
| 3 | CC | | | 0 |
| 4 | DD | | | 0 |
+----------------+------+-------+-------+--------+
In case that the id (unit1) does not exists in tableC or tableD, 'split_position' and 'code' associated should appear but in the 'active' field should appear a 0.
it's a bit of a steep learning curve, but basically you have to declare a cursor and loop
over the each row in the ordertable and select your data then UNION the result together using dynamic SQL.
check this sqlFiddle
to order by final result by split position ASC just add ORDER BY split_position ASC to the sql variable before executing it like this sqlFiddle
to solve your problem you would need something like the following:
select split_position, code, name, time, active
from
(
select 'tableA' as tablename, id, [name], [time], active
from tableA
union all select 'tableB' as tablename, id, [name], [time], active
from tableB
) as tbls
inner join alltables atbls
on tbls.tablename=atbls.name
inner join ordertable ot
on atbls.code=ot.code
where tbls.id='unit1'

How to query for all information of an entity within an Entity-Attribute-Value (EAV) model?

I've searched about this and tried to make it myself over the last few days but I just couldn't. The closest I've gotten within my search was this answer, also on Stack Overflow: EAV Select query from spreaded value tables
So here I am, turning myself to the Internet!
So, I have a database which makes use of the EAV (Entity-Attribute-Value) model. But here's the catch: the actual entities aren't directly connected to the other EAV tables. Let me be more specific; say that there is a Person and a Site tables, and that they only have their primary keys: person_id and site_id, respectively.
Because the attributes (called "properties" on my schema) of those entities (i.e. the Person and the Site) must be dynamic, they must all be stored outside their respective tables, i.e. the EAV tables. The following is the EAV part of the database schema (I'm not sure if it's completely correct, so please let me know if you have any suggestion). -- http://i.stack.imgur.com/EN3dy.png
The EAV part of the schema basically has the following tables:
property
property_value_varchar
property_value_text
property_value_number
property_value_boolean
property_value_datetime
entity_tables
Ok, so, since the Entities aren't "directly connected" to the EAV part, I'm using the entity_tables table just as a reference to the actual tables, so, with the example above, the entity_tables table should look something like this:
---------------------------------------
|entity_table_id | entity_table_name |
| 1 | person |
| 2 | site |
| . | . |
| . | . |
---------------------------------------
The property table is the one that actually holds the different properties that any entity can hold, say "PERSON_FIRST_NAME" or "LOCATION_NAME", or anything else.
The property_value_* tables are all exactly the same except on the datatype of the property_value. These are the ones that hold the actual value of each Entity's object's property, which get mapped by the entity_table_id and entity_object_id.
Let me give you a possible instance of the database, for clarity:
Person table
-------------
| person_id |
| 1 |
| 2 |
-------------
Site table
-----------
| site_id |
| 1 |
| 2 |
-----------
entity_tables table
---------------------------------------
|entity_table_id | entity_table_name |
| 1 | person |
| 2 | site |
---------------------------------------
property table
-------------------------------------
| property_id | property_code |
| 1 | PERSON_FIRST_NAME |
| 2 | PERSON_LAST_NAME |
| 3 | PERSON_BIRTH_DATE |
| 4 | SITE_NAME |
| 5 | SITE_PHONE_NR_1 |
| 6 | SITE_PHONE_NR_2 |
| 7 | SITE_LATITUDE |
| 8 | SITE_LONGITUDE |
| 9 | SITE_CITY |
| 10 | SITE_COUNTRY |
| 11 | SITE_ZIP_CODE |
-------------------------------------
property_value_varchar table
-----------------------------------------------------------------------------------------
| property_value_id | property_id | entity_table_id | entity_object_id | property_value |
| 1 | 1 | 1 | 1 | Richard |
| 2 | 2 | 1 | 1 | Hammer |
| 3 | 1 | 1 | 2 | Bruce |
| 4 | 2 | 1 | 2 | Heaton |
| 5 | 4 | 2 | 1 | BatCave |
| 6 | 5 | 2 | 1 | +49123456789 |
| 7 | 4 | 2 | 2 | BigCompany |
| 8 | 5 | 2 | 2 | 987654321 |
| 9 | 6 | 2 | 2 | 147852369 |
| 10 | 9 | 2 | 2 | Berlin |
| 11 | 10 | 2 | 2 | Germany |
| 12 | 11 | 2 | 2 | 14167 |
-----------------------------------------------------------------------------------------
property_value_datetime table
-----------------------------------------------------------------------------------------
| property_value_id | property_id | entity_table_id | entity_object_id | property_value |
| 1 | 3 | 1 | 1 | 1985-05-31 |
-----------------------------------------------------------------------------------------
property_value_number table
-----------------------------------------------------------------------------------------
| property_value_id | property_id | entity_table_id | entity_object_id | property_value |
| 1 | 7 | 2 | 1 | 1.402636 |
| 2 | 8 | 2 | 1 | 7.273922 |
-----------------------------------------------------------------------------------------
(property_value_text and property_value_boolean tables are empty)
As you could see, not all objects of each entity have necessarily the same properties (attributes). The domain is really loose like that.
So, now like so many people before me, I'm not sure how to retrieve all of this information in a readable way, namely how can I get all of the information concerning the records of the Person table or of the Site table?
Namely, how can I get something like this:
Person table view
----------------------------------------------------
| Person ID | Property code | Property value |
| 1 | PERSON_FIRST_NAME | Richard |
| 1 | PERSON_LAST_NAME | Hammer |
| 1 | PERSON_BIRTH_DATE | 1985-05-31 |
| 2 | PERSON_FIRST_NAME | Bruce |
| 2 | PERSON_LAST_NAME | Heaton |
----------------------------------------------------
Site table view
------------------------------------------------
| Site ID | Property code | Property value |
| 1 | SITE_NAME | Batcave |
| 1 | SITE_PHONE_NR_1 | +49123456789 |
| 1 | SITE_LATITUDE | 1.402636 |
| 1 | SITE_LONGITUDE | 7.273922 |
| 2 | SITE_NAME | BigCompany |
| 2 | SITE_PHONE_NR_1 | 987654321 |
| 2 | SITE_PHONE_NR_2 | 147852369 |
| 2 | SITE_CITY | Berlin |
| 2 | SITE_COUNTRY | Germany |
| 2 | SITE_ZIP_CODE | 14167 |
------------------------------------------------
Or even like this, if it is easier:
Person table view
------------------------------------------------------------------------
| Person ID | PERSON_FIRST_NAME | PERSON_LAST_NAME | PERSON_BIRTH_DATE |
| 1 | Richard | Hammer | 1985-05-31 |
| 2 | Bruce | Heaton | |
------------------------------------------------------------------------
Site table view
----------------------------------------------------------------------------------------------------------------------------------------
| Site ID | SITE_NAME | SITE_PHONE_NR_1 | SITE_PHONE_NR_2 | SITE_LATITUDE | SITE_LONGITUDE | SITE_CITY | SITE_COUNTRY | SITE_ZIP_CODE |
| 1 | Batcave | +49123456789 | | 1.402636 | 7.273922 | | | |
| 2 | BigCompany | 987654321 | 147852369 | | | Berlin | Germany | 14167 |
----------------------------------------------------------------------------------------------------------------------------------------
I realize this can be quite confusing. Please let me know how else I can help you help me, like more information or better explaining of some part.
I also don't expect 1 SQL query (per entity) to do the trick. I realize that more than 1 query is likely and that it/they would very likely need to be "assembled" by PHP (for instance), in order to really make it dynamic. So even if someone could even just explain me how I could get all of this info just for the hypothetical properties (attribute) that I have above, I would already be immensely grateful!
Thank you for any help!
This was a fun question! This can be handled with dynamic sql. In the code below, the schema has been recreated with temp tables. The code could be turned into a stored procedure that takes an entity_table_id as a parameter and then selects the entity_object_id as entity_table_name + 'id' followed by every property_value as columns with the corresponding property_code as the headings.
-- load EAV tables
if object_id('tempdb..#entity_tables') is not null
drop table #entity_tables
create table #entity_tables(entity_table_id int,entity_table_name varchar(255))
insert into #entity_tables values
(1,'person'),
(2,'site')
if object_id('tempdb..#property') is not null
drop table #property
create table #property(property_id int,property_code varchar(255))
insert into #property values
(1,'PERSON_FIRST_NAME'),
(2,'PERSON_LAST_NAME'),
(3,'PERSON_BIRTH_DATE'),
(4,'SITE_NAME'),
(5,'SITE_PHONE_NR_1'),
(6,'SITE_PHONE_NR_2'),
(7,'SITE_LATITUDE'),
(8,'SITE_LONGITUDE'),
(9,'SITE_CITY'),
(10,'SITE_COUNTRY'),
(11,'SITE_ZIP_CODE')
if object_id('tempdb..#property_value_varchar') is not null
drop table #property_value_varchar
create table #property_value_varchar(property_value_id int,property_id int,entity_table_id int,entity_object_id int,property_value varchar(255))
insert into #property_value_varchar values
(1,1,1,1,'Richard'),
(2,2,1,1,'Hammer'),
(3,1,1,2,'Bruce'),
(4,2,1,2,'Heaton'),
(5,4,2,1,'BatCave'),
(6,5,2,1,'+49123456789'),
(7,4,2,2,'BigCompany'),
(8,5,2,2,'987654321'),
(9,6,2,2,'147852369'),
(10,9,2,2,'Berlin'),
(11,10,2,2,'Germany'),
(12,11,2,2,'14167')
if object_id('tempdb..#property_value_datetime') is not null
drop table #property_value_datetime
create table #property_value_datetime(property_value_id int,property_id int,entity_table_id int,entity_object_id int,property_value datetime)
insert into #property_value_datetime values
(1,3,1,1,'1985-05-31')
if object_id('tempdb..#property_value_number') is not null
drop table #property_value_number
create table #property_value_number(property_value_id int,property_id int,entity_table_id int,entity_object_id int,property_value float)
insert into #property_value_number values
(1,7,2,1,1.402636),
(2,8,2,1,7.273922)
-- create dynamic sql to get all data conditioned on #entity_tables.table_id value
declare #tableid int,#sql varchar(max)
set #tableid = 1 -- this could be passed as a parameter
-- get pivot code with #ColumnList# placeholders to be added below
select #sql = 'select entity_object_id ' + entity_table_name + 'id,
#ColumnListCast#
from (
select
e.entity_table_name,
pv.entity_object_id,
pv.property_value,
p.property_code
from #entity_tables e
inner join (
select entity_table_id,entity_object_id,property_id,property_value from #property_value_varchar union all
select entity_table_id,entity_object_id,property_id,cast(property_value as varchar(255)) from #property_value_datetime union all
select entity_table_id,entity_object_id,property_id,cast(property_value as varchar(255)) from #property_value_number
) pv
on pv.entity_table_id = e.entity_table_id
inner join #property p
on p.property_id = pv.property_id
where e.entity_table_id = ' + cast(#tableid as varchar(5)) + '
) p
pivot (
max(property_value)
for property_code in (
#ColumnList#
)
) piv' from #entity_tables where entity_table_id = #tableid
-- get column list with cast version for diffferent data types
declare #ColumnList varchar(max),
#ColumnListCast nvarchar(max)
set #ColumnList = ''
set #ColumnListCast = ''
select #ColumnList = #ColumnList + '[' + p.property_code + ']' + case row_number() over(order by p.property_id desc) when 1 then '' else ',' end,
#ColumnListCast = #ColumnListCast + 'cast([' + p.property_code + '] as ' + t.CastValue + ') [' + p.property_code + ']' + case row_number() over(order by p.property_id desc) when 1 then '' else ',' end
from #property p
inner join (
select property_id,'varchar(255)' CastValue from #property_value_varchar where entity_table_id = #tableid union
select property_id,'datetime' CastValue from #property_value_datetime where entity_table_id = #tableid union
select property_id,'float' CastValue from #property_value_number where entity_table_id = #tableid
) t
on t.property_id = p.property_id
order by p.property_id
set #sql = replace(replace(#sql,'#ColumnList#',#ColumnList),'#ColumnListCast#',#ColumnListCast)
exec(#sql)